diff --git a/cmd/cogito/main_test.go b/cmd/cogito/main_test.go index da6f2a8..e9597e7 100644 --- a/cmd/cogito/main_test.go +++ b/cmd/cogito/main_test.go @@ -63,6 +63,10 @@ func TestRunPutSuccess(t *testing.T) { var ghReq github.AddRequest var ghUrl *url.URL gitHubSpy := testhelp.SpyHttpServer(&ghReq, nil, &ghUrl, http.StatusCreated) + gitHubSpyURL, err := url.Parse(gitHubSpy.URL) + if err != nil { + t.Fatalf("error parsing SpyHttpServer URL: %s", err) + } var chatMsg googlechat.BasicMessage chatReply := googlechat.MessageReply{} var gchatUrl *url.URL @@ -72,6 +76,7 @@ func TestRunPutSuccess(t *testing.T) { Owner: "the-owner", Repo: "the-repo", AccessToken: "the-secret", + GhHostname: gitHubSpyURL.Host, GChatWebHook: googleChatSpy.URL, LogLevel: "debug", }, @@ -80,9 +85,9 @@ func TestRunPutSuccess(t *testing.T) { var out bytes.Buffer var logOut bytes.Buffer inputDir := testhelp.MakeGitRepoFromTestdata(t, "../../cogito/testdata/one-repo/a-repo", - testhelp.HttpsRemote("github.com", "the-owner", "the-repo"), "dummySHA", wantGitRef) + testhelp.HttpsRemote(gitHubSpyURL.Host, "the-owner", "the-repo"), "dummySHA", wantGitRef) - err := mainErr(in, &out, &logOut, []string{"out", inputDir}) + err = mainErr(in, &out, &logOut, []string{"out", inputDir}) assert.NilError(t, err, "\nout: %s\nlogOut: %s", out.String(), logOut.String()) // diff --git a/cogito/ghcommitsink.go b/cogito/ghcommitsink.go index 37c7e9d..93091ad 100644 --- a/cogito/ghcommitsink.go +++ b/cogito/ghcommitsink.go @@ -41,6 +41,7 @@ func (sink GitHubCommitStatusSink) Send() error { context := ghMakeContext(sink.Request) target := &github.Target{ + Server: "http://" + sink.Request.Source.GhHostname, Retry: retry.Retry{ FirstDelay: retryFirstDelay, BackoffLimit: retryBackoffLimit, diff --git a/cogito/ghcommitsink_test.go b/cogito/ghcommitsink_test.go index 5188f68..d74c0fc 100644 --- a/cogito/ghcommitsink_test.go +++ b/cogito/ghcommitsink_test.go @@ -23,16 +23,21 @@ func TestSinkGitHubCommitStatusSendSuccess(t *testing.T) { var ghReq github.AddRequest var URL *url.URL ts := testhelp.SpyHttpServer(&ghReq, nil, &URL, http.StatusCreated) + gitHubSpyURL, err := url.Parse(ts.URL) + if err != nil { + t.Fatalf("error parsing SpyHttpServer URL: %s", err) + } sink := cogito.GitHubCommitStatusSink{ Log: hclog.NewNullLogger(), GitRef: wantGitRef, Request: cogito.PutRequest{ + Source: cogito.Source{GhHostname: gitHubSpyURL.Host}, Params: cogito.PutParams{State: wantState}, Env: cogito.Environment{BuildJobName: jobName}, }, } - err := sink.Send() + err = sink.Send() assert.NilError(t, err) ts.Close() // Avoid races before the following asserts. @@ -46,16 +51,21 @@ func TestSinkGitHubCommitStatusSendFailure(t *testing.T) { http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusTeapot) })) + gitHubSpyURL, err := url.Parse(ts.URL) + if err != nil { + t.Fatalf("error parsing SpyHttpServer URL: %s", err) + } defer ts.Close() sink := cogito.GitHubCommitStatusSink{ Log: hclog.NewNullLogger(), GitRef: "deadbeefdeadbeef", Request: cogito.PutRequest{ + Source: cogito.Source{GhHostname: gitHubSpyURL.Host}, Params: cogito.PutParams{State: cogito.StatePending}, }, } - err := sink.Send() + err = sink.Send() assert.ErrorContains(t, err, `failed to add state "pending" for commit deadbee: 418 I'm a teapot`) diff --git a/cogito/protocol.go b/cogito/protocol.go index ac0b2d9..ab70b33 100644 --- a/cogito/protocol.go +++ b/cogito/protocol.go @@ -164,6 +164,7 @@ type Source struct { // // Optional // + GhHostname string `json:"github_hostname"` GChatWebHook string `json:"gchat_webhook"` // SENSITIVE LogLevel string `json:"log_level"` LogUrl string `json:"log_url"` // DEPRECATED @@ -179,6 +180,7 @@ func (src Source) String() string { fmt.Fprintf(&bld, "owner: %s\n", src.Owner) fmt.Fprintf(&bld, "repo: %s\n", src.Repo) + fmt.Fprintf(&bld, "github_hostname: %s\n", src.GhHostname) fmt.Fprintf(&bld, "access_token: %s\n", redact(src.AccessToken)) fmt.Fprintf(&bld, "gchat_webhook: %s\n", redact(src.GChatWebHook)) fmt.Fprintf(&bld, "log_level: %s\n", src.LogLevel) diff --git a/cogito/protocol_test.go b/cogito/protocol_test.go index 508910a..4392849 100644 --- a/cogito/protocol_test.go +++ b/cogito/protocol_test.go @@ -175,6 +175,7 @@ func TestSourcePrintLogRedaction(t *testing.T) { source := cogito.Source{ Owner: "the-owner", Repo: "the-repo", + GhHostname: "github.com", AccessToken: "sensitive-the-access-token", GChatWebHook: "sensitive-gchat-webhook", LogLevel: "debug", @@ -186,6 +187,7 @@ func TestSourcePrintLogRedaction(t *testing.T) { t.Run("fmt.Print redacts fields", func(t *testing.T) { want := `owner: the-owner repo: the-repo +github_hostname: github.com access_token: ***REDACTED*** gchat_webhook: ***REDACTED*** log_level: debug @@ -205,6 +207,7 @@ sinks: []` } want := `owner: the-owner repo: +github_hostname: access_token: gchat_webhook: log_level: diff --git a/cogito/put_test.go b/cogito/put_test.go index 3bcac49..294494a 100644 --- a/cogito/put_test.go +++ b/cogito/put_test.go @@ -267,7 +267,7 @@ func TestPutterProcessInputDirSuccess(t *testing.T) { "https://github.com/dummy-owner/dummy-repo", "dummySHA", "banana") putter.InputDir = filepath.Join(tmpDir, filepath.Base(tc.inputDir)) putter.Request = cogito.PutRequest{ - Source: cogito.Source{Owner: "dummy-owner", Repo: "dummy-repo", Sinks: tc.sink}, + Source: cogito.Source{GhHostname: "github.com", Owner: "dummy-owner", Repo: "dummy-repo", Sinks: tc.sink}, Params: tc.params, } @@ -319,7 +319,7 @@ func TestPutterProcessInputDirFailure(t *testing.T) { "https://github.com/dummy-owner/dummy-repo", "dummySHA", "banana mango") putter := cogito.NewPutter(hclog.NewNullLogger()) putter.Request = cogito.PutRequest{ - Source: cogito.Source{Owner: "dummy-owner", Repo: "dummy-repo"}, + Source: cogito.Source{GhHostname: "github.com", Owner: "dummy-owner", Repo: "dummy-repo"}, Params: tc.params, } putter.InputDir = filepath.Join(tmpDir, filepath.Base(tc.inputDir)) diff --git a/cogito/putter.go b/cogito/putter.go index 406dccc..496f883 100644 --- a/cogito/putter.go +++ b/cogito/putter.go @@ -131,7 +131,7 @@ func (putter *ProdPutter) ProcessInputDir() error { case 1: repoDir := filepath.Join(putter.InputDir, inputDirs.OrderedList()[0]) putter.log.Debug("", "inputDirs", inputDirs, "repoDir", repoDir, "msgDir", msgDir) - if err := checkGitRepoDir(repoDir, source.Owner, source.Repo); err != nil { + if err := checkGitRepoDir(repoDir, source.GhHostname, source.Owner, source.Repo); err != nil { return err } putter.gitRef, err = getGitCommit(repoDir) @@ -237,7 +237,7 @@ func collectInputDirs(dir string) ([]string, error) { // - The repo configuration contains a "remote origin" section. // - The remote origin url can be parsed following the GitHub conventions. // - The result of the parse matches OWNER and REPO. -func checkGitRepoDir(dir, owner, repo string) error { +func checkGitRepoDir(dir, hostname, owner, repo string) error { cfg, err := mini.LoadConfiguration(filepath.Join(dir, ".git/config")) if err != nil { return fmt.Errorf("parsing .git/config: %w", err) @@ -259,7 +259,7 @@ func checkGitRepoDir(dir, owner, repo string) error { if err != nil { return fmt.Errorf(".git/config: remote: %w", err) } - left := []string{"github.com", owner, repo} + left := []string{hostname, owner, repo} right := []string{gu.URL.Host, gu.Owner, gu.Repo} for i, l := range left { r := right[i] @@ -272,10 +272,11 @@ Git repository configuration (received as 'inputs:' in this PUT step): repo: %s Cogito SOURCE configuration: + hostname: %s owner: %s repo: %s`, gitUrl, gu.Owner, gu.Repo, - owner, repo) + hostname, owner, repo) } } return nil diff --git a/cogito/putter_private_test.go b/cogito/putter_private_test.go index 0abc373..9570fce 100644 --- a/cogito/putter_private_test.go +++ b/cogito/putter_private_test.go @@ -2,6 +2,7 @@ package cogito import ( "errors" + "fmt" "net/url" "os" "path/filepath" @@ -65,6 +66,7 @@ func TestCheckGitRepoDirSuccess(t *testing.T) { repoURL string } + const wantHostname = "github.com" const wantOwner = "smiling" const wantRepo = "butterfly" @@ -73,7 +75,7 @@ func TestCheckGitRepoDirSuccess(t *testing.T) { "dummySHA", "dummyHead") err := checkGitRepoDir(filepath.Join(inputDir, filepath.Base(tc.dir)), - wantOwner, wantRepo) + wantHostname, wantOwner, wantRepo) assert.NilError(t, err) } @@ -82,22 +84,22 @@ func TestCheckGitRepoDirSuccess(t *testing.T) { { name: "repo with good SSH remote", dir: "testdata/one-repo/a-repo", - repoURL: testhelp.SshRemote("github.com", wantOwner, wantRepo), + repoURL: testhelp.SshRemote(wantHostname, wantOwner, wantRepo), }, { name: "repo with good HTTPS remote", dir: "testdata/one-repo/a-repo", - repoURL: testhelp.HttpsRemote("github.com", wantOwner, wantRepo), + repoURL: testhelp.HttpsRemote(wantHostname, wantOwner, wantRepo), }, { name: "repo with good HTTP remote", dir: "testdata/one-repo/a-repo", - repoURL: testhelp.HttpRemote("github.com", wantOwner, wantRepo), + repoURL: testhelp.HttpRemote(wantHostname, wantOwner, wantRepo), }, { name: "PR resource but with basic auth in URL (see PR #46)", dir: "testdata/one-repo/a-repo", - repoURL: "https://x-oauth-basic:ghp_XXX@github.com/smiling/butterfly.git", + repoURL: fmt.Sprintf("https://x-oauth-basic:ghp_XXX@%s/%s/%s.git", wantHostname, wantOwner, wantRepo), }, } @@ -114,6 +116,7 @@ func TestCheckGitRepoDirFailure(t *testing.T) { wantErrWild string // wildcard matching } + const wantHostname = "github.com" const wantOwner = "smiling" const wantRepo = "butterfly" @@ -122,7 +125,7 @@ func TestCheckGitRepoDirFailure(t *testing.T) { "dummySHA", "dummyHead") err := checkGitRepoDir(filepath.Join(inDir, filepath.Base(tc.dir)), - wantOwner, wantRepo) + wantHostname, wantOwner, wantRepo) assert.ErrorContains(t, err, tc.wantErrWild) } @@ -152,6 +155,7 @@ Git repository configuration (received as 'inputs:' in this PUT step): repo: repo-a Cogito SOURCE configuration: + hostname: github.com owner: smiling repo: butterfly`, }, @@ -167,6 +171,7 @@ Git repository configuration (received as 'inputs:' in this PUT step): repo: repo-a Cogito SOURCE configuration: + hostname: github.com owner: smiling repo: butterfly`, },