@@ -2,89 +2,132 @@ package main
22
33import (
44 "C"
5- "log"
6-
5+ "bufio"
76 "fmt"
7+ "io"
88 "io/ioutil"
9+ "log"
10+ "net"
11+ "net/url"
912 "os"
13+ "path/filepath"
14+ "strings"
15+ "time"
1016
1117 // git2go must be aligned with libgit2 version:
1218 // https://github.com/libgit2/git2go#which-go-version-to-use
1319 git2go "github.com/libgit2/git2go/v33"
14- )
15- import (
16- "bufio"
17- "io"
18- "net"
19- "path/filepath"
20- "strings"
2120
22- "golang.org/x/crypto/ssh"
21+ "github.com/fluxcd/pkg/gittestserver"
22+ "github.com/fluxcd/pkg/ssh"
23+ "github.com/fluxcd/source-controller/pkg/git"
24+ cryptossh "golang.org/x/crypto/ssh"
2325 "golang.org/x/crypto/ssh/knownhosts"
2426)
2527
26- const keysDir = "/root/smoketest/keys"
27- const host = "github.com"
28-
29- // ssh-keyscan -t ecdsa github.com
30- const knownHost_ecdsa = `# github.com:22 SSH-2.0-babeld-b6e6da7b
31- github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=`
32-
33- // fingerprints can be validated against:
34- // https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints
35-
36- // TODO: setup SSH test servers to force and test rsa/ed25519 support
37- // ssh-keyscan -t rsa github.com
38- const knownHost_rsa = `# github.com:22 SSH-2.0-babeld-b6e6da7b
39- github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==`
40-
41- // ssh-keyscan -t ed25519 github.com
42- const knownHost_ed25519 = `# github.com:22 SSH-2.0-babeld-b6e6da7b
43- github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl`
28+ const testsDir = "/root/tests"
4429
4530func main () {
4631 fmt .Println ("Running tests..." )
47- os .MkdirAll ("/root/tests" , 0o755 )
32+ os .MkdirAll (testsDir , 0o755 )
33+ defer os .RemoveAll (testsDir )
34+
35+ repoPath := "test.git"
36+ server := createTestServer (repoPath )
37+ if err := server .StartHTTP (); err != nil {
38+ panic (fmt .Errorf ("StartHTTP: %w" , err ))
39+ }
40+ defer server .StopHTTP ()
4841
42+ httpRepoURL := fmt .Sprintf ("%s/%s" , server .HTTPAddressWithCredentials (), repoPath )
4943 test ("HTTPS clone with no options" ,
50- "/root/tests/ https-clone-no-options" ,
51- "https://github.com/fluxcd/golang-with-libgit2" ,
44+ filepath . Join ( testsDir , "/ https-clone-no-options") ,
45+ httpRepoURL ,
5246 & git2go.CloneOptions {Bare : true })
5347
48+ if err := server .ListenSSH (); err != nil {
49+ panic (fmt .Errorf ("listenSSH: %w" , err ))
50+ }
51+ go func () {
52+ server .StartSSH ()
53+ }()
54+ defer server .StopSSH ()
55+
56+ u , err := url .Parse (server .SSHAddress ())
57+ if err != nil {
58+ panic (fmt .Errorf ("ssh url Parse: %w" , err ))
59+ }
60+ knownHosts , err := ssh .ScanHostKey (u .Host , 5 * time .Second )
61+ if err != nil {
62+ panic (fmt .Errorf ("scan host key: %w" , err ))
63+ }
64+
65+ sshRepoURL := fmt .Sprintf ("%s/%s" , server .SSHAddress (), repoPath )
66+
67+ rsa , err := ssh .NewRSAGenerator (4096 ).Generate ()
68+ if err != nil {
69+ panic (fmt .Errorf ("generating rsa key: %w" , err ))
70+ }
71+
5472 test ("SSH clone with rsa key" ,
55- "/root/tests/ ssh-clone-rsa" ,
56- "git@github.com:pjbgf/pkg.git" ,
73+ filepath . Join ( testsDir , "/ ssh-clone-rsa") ,
74+ sshRepoURL ,
5775 & git2go.CloneOptions {
5876 Bare : true ,
5977 FetchOptions : git2go.FetchOptions {
6078 RemoteCallbacks : git2go.RemoteCallbacks {
6179 CredentialsCallback : func (url string , username string , allowedTypes git2go.CredentialType ) (* git2go.Credential , error ) {
62- credential , e := git2go .NewCredentialSSHKey ("git" , keyPath ( "id_rsa.pub" ), keyPath ( "id_rsa" ), "" )
63- return credential , e
80+ return git2go .NewCredentialSSHKeyFromMemory ("git" ,
81+ string ( rsa . PublicKey ), string ( rsa . PrivateKey ), "" )
6482 },
65- CertificateCheckCallback : knownHostsCallback (host , [] byte ( knownHost_ecdsa ) ),
83+ CertificateCheckCallback : knownHostsCallback (u . Host , knownHosts ),
6684 },
67- }})
85+ },
86+ })
6887
69- //TODO: Add test ssh server to remove dependency on having a repo with specific keys registered.
88+ ed25519 , err := ssh .NewEd25519Generator ().Generate ()
89+ if err != nil {
90+ panic (fmt .Errorf ("generating ed25519 key: %w" , err ))
91+ }
7092 test ("SSH clone with ed25519 key" ,
71- "/root/tests/ ssh-clone-ed25519" ,
72- "git@github.com:pjbgf/pkg.git" ,
93+ filepath . Join ( testsDir , "/ ssh-clone-ed25519") ,
94+ sshRepoURL ,
7395 & git2go.CloneOptions {
7496 Bare : true ,
7597 FetchOptions : git2go.FetchOptions {
7698 RemoteCallbacks : git2go.RemoteCallbacks {
7799 CredentialsCallback : func (url string , username string , allowedTypes git2go.CredentialType ) (* git2go.Credential , error ) {
78- credential , e := git2go .NewCredentialSSHKey ("git" , keyPath ( "id_ed25519.pub" ), keyPath ( "id_ed25519" ), "" )
79- return credential , e
100+ return git2go .NewCredentialSSHKeyFromMemory ("git" ,
101+ string ( ed25519 . PublicKey ), string ( ed25519 . PrivateKey ), "" )
80102 },
81- CertificateCheckCallback : knownHostsCallback (host , [] byte ( knownHost_ecdsa ) ),
103+ CertificateCheckCallback : knownHostsCallback (u . Host , knownHosts ),
82104 },
83- }})
105+ },
106+ })
107+
108+ //TODO: Expand tests to consider supported algorithms/hashes for hostKey verification.
84109}
85110
86- func keyPath (keyName string ) string {
87- return filepath .Join (keysDir , keyName )
111+ func createTestServer (repoPath string ) * gittestserver.GitServer {
112+ fmt .Println ("Creating gitserver for SSH tests..." )
113+ server , err := gittestserver .NewTempGitServer ()
114+ if err != nil {
115+ panic (fmt .Errorf ("creating git test server: %w" , err ))
116+ }
117+ defer os .RemoveAll (server .Root ())
118+
119+ server .Auth ("test-user" , "test-pswd" )
120+ server .AutoCreate ()
121+ server .KeyDir (filepath .Join (server .Root (), "keys" ))
122+
123+ os .MkdirAll ("testdata/git/repo" , 0o755 )
124+ os .WriteFile ("testdata/git/repo/test123" , []byte ("test..." ), 0o644 )
125+ os .WriteFile ("testdata/git/repo/test321" , []byte ("test2..." ), 0o644 )
126+
127+ if err = server .InitRepo ("testdata/git/repo" , git .DefaultBranch , repoPath ); err != nil {
128+ panic (fmt .Errorf ("InitRepo: %w" , err ))
129+ }
130+ return server
88131}
89132
90133func test (description , targetDir , repoURI string , cloneOptions * git2go.CloneOptions ) {
@@ -150,14 +193,14 @@ func knownHostsCallback(host string, knownHosts []byte) git2go.CertificateCheckC
150193
151194type knownKey struct {
152195 hosts []string
153- key ssh .PublicKey
196+ key cryptossh .PublicKey
154197}
155198
156199func parseKnownHosts (s string ) ([]knownKey , error ) {
157200 var knownHosts []knownKey
158201 scanner := bufio .NewScanner (strings .NewReader (s ))
159202 for scanner .Scan () {
160- _ , hosts , pubKey , _ , _ , err := ssh .ParseKnownHosts (scanner .Bytes ())
203+ _ , hosts , pubKey , _ , _ , err := cryptossh .ParseKnownHosts (scanner .Bytes ())
161204 if err != nil {
162205 // Lines that aren't host public key result in EOF, like a comment
163206 // line. Continue parsing the other lines.
@@ -188,8 +231,8 @@ func (k knownKey) matches(host string, hostkey git2go.HostkeyCertificate) bool {
188231 }
189232
190233 if hostkey .Kind & git2go .HostkeySHA256 > 0 {
191- knownFingerprint := ssh .FingerprintSHA256 (k .key )
192- returnedFingerprint := ssh .FingerprintSHA256 (hostkey .SSHPublicKey )
234+ knownFingerprint := cryptossh .FingerprintSHA256 (k .key )
235+ returnedFingerprint := cryptossh .FingerprintSHA256 (hostkey .SSHPublicKey )
193236
194237 fmt .Printf ("known and found fingerprints:\n %q\n %q\n " ,
195238 knownFingerprint ,
0 commit comments