-
Notifications
You must be signed in to change notification settings - Fork 2.1k
cli/config/credentials: refactor DetectDefaultStore and add tests #5568
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,14 +16,56 @@ func DetectDefaultStore(customStore string) string { | |
| // use user-defined | ||
| return customStore | ||
| } | ||
| if preferred := findPreferredHelper(); preferred != "" { | ||
| return preferred | ||
| } | ||
| if defaultHelper == "" { | ||
| return "" | ||
| } | ||
| if _, err := exec.LookPath(remoteCredentialsPrefix + defaultHelper); err != nil { | ||
| return "" | ||
| } | ||
| return defaultHelper | ||
| } | ||
|
|
||
| // overridePreferred is used to override the preferred helper in tests. | ||
| var overridePreferred string | ||
|
|
||
| platformDefault := defaultCredentialsStore() | ||
| if platformDefault == "" { | ||
| // findPreferredHelper detects whether the preferred credentials-store and | ||
| // its helper binaries are installed. It returns the name of the preferred | ||
| // store if found, otherwise returns an empty string to fall back to resolving | ||
| // the default helper. | ||
| // | ||
| // Note that the logic below is currently specific to detection needed for the | ||
| // "pass" credentials-helper on Linux (which is the only platform with a preferred | ||
| // helper). It is put in a non-platform specific file to allow running tests | ||
| // on other platforms. | ||
| func findPreferredHelper() string { | ||
| preferred := preferredHelper | ||
| if overridePreferred != "" { | ||
| preferred = overridePreferred | ||
| } | ||
| if preferred == "" { | ||
| return "" | ||
| } | ||
|
|
||
| if _, err := exec.LookPath(remoteCredentialsPrefix + platformDefault); err != nil { | ||
| // Note that the logic below is specific to detection needed for the | ||
| // "pass" credentials-helper on Linux (which is the only platform with | ||
| // a "preferred" and "default" helper. This logic may change if a similar | ||
| // order of preference is needed on other platforms. | ||
|
Comment on lines
+52
to
+55
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "detection" logic below is generic, right? It's only used for linux (because linux is the only platform with a preferred helper), but would work for any other platform all the same?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. // a "preferred" and "default" helper. This logic may change if a similar
// order of preference is needed on other platforms.If this comment as a whole is about the
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
AAAHH, this is about checking for both
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I realize you moved this here in order to make this easier to test cross-platform, but this is exactly the type of thing that would make sense to put in a |
||
|
|
||
| // If we don't have the preferred helper installed, there's no need | ||
| // to check if its dependencies are installed, instead, try to | ||
| // use the default credentials-helper for this platform (if installed). | ||
| if _, err := exec.LookPath(remoteCredentialsPrefix + preferred); err != nil { | ||
| return "" | ||
| } | ||
| return platformDefault | ||
|
|
||
| // Detect if the helper binary is present as well. This is needed for | ||
| // the "pass" credentials helper, which uses this binary. | ||
| if _, err := exec.LookPath(preferred); err != nil { | ||
| return "" | ||
| } | ||
|
|
||
| return preferred | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| package credentials | ||
|
|
||
| func defaultCredentialsStore() string { | ||
| return "osxkeychain" | ||
| } | ||
| const ( | ||
| preferredHelper = "" | ||
| defaultHelper = "osxkeychain" | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,6 @@ | ||
| package credentials | ||
|
|
||
| import ( | ||
| "os/exec" | ||
| const ( | ||
| preferredHelper = "pass" | ||
| defaultHelper = "secretservice" | ||
| ) | ||
|
|
||
| func defaultCredentialsStore() string { | ||
| if _, err := exec.LookPath("pass"); err == nil { | ||
| return "pass" | ||
| } | ||
|
|
||
| return "secretservice" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| package credentials | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "testing" | ||
|
|
||
| "gotest.tools/v3/assert" | ||
| ) | ||
|
|
||
| func TestDetectDefaultStore(t *testing.T) { | ||
| tmpDir := t.TempDir() | ||
| t.Setenv("PATH", tmpDir) | ||
|
|
||
| t.Run("none available", func(t *testing.T) { | ||
| const expected = "" | ||
| assert.Equal(t, expected, DetectDefaultStore("")) | ||
| }) | ||
| t.Run("custom helper", func(t *testing.T) { | ||
| const expected = "my-custom-helper" | ||
| assert.Equal(t, expected, DetectDefaultStore(expected)) | ||
|
|
||
| // Custom helper should be used even if the actual helper exists | ||
| createFakeHelper(t, filepath.Join(tmpDir, remoteCredentialsPrefix+defaultHelper)) | ||
| assert.Equal(t, expected, DetectDefaultStore(expected)) | ||
| }) | ||
| t.Run("default", func(t *testing.T) { | ||
| createFakeHelper(t, filepath.Join(tmpDir, remoteCredentialsPrefix+defaultHelper)) | ||
| expected := defaultHelper | ||
| assert.Equal(t, expected, DetectDefaultStore("")) | ||
| }) | ||
|
|
||
| // On Linux, the "pass" credentials helper requires both a "pass" binary | ||
| // to be present and a "docker-credentials-pass" credentials helper to | ||
| // be installed. | ||
| t.Run("preferred helper", func(t *testing.T) { | ||
| // Create the default helper as we need it for the fallback. | ||
| createFakeHelper(t, filepath.Join(tmpDir, remoteCredentialsPrefix+defaultHelper)) | ||
|
|
||
| const testPreferredHelper = "preferred" | ||
| overridePreferred = testPreferredHelper | ||
|
|
||
| // Use preferred helper if both binaries exist. | ||
| t.Run("success", func(t *testing.T) { | ||
| createFakeHelper(t, filepath.Join(tmpDir, testPreferredHelper)) | ||
| createFakeHelper(t, filepath.Join(tmpDir, remoteCredentialsPrefix+testPreferredHelper)) | ||
| expected := testPreferredHelper | ||
| assert.Equal(t, expected, DetectDefaultStore("")) | ||
| }) | ||
|
|
||
| // Fall back to the default helper if the preferred credentials-helper isn't installed. | ||
| t.Run("not installed", func(t *testing.T) { | ||
| createFakeHelper(t, filepath.Join(tmpDir, remoteCredentialsPrefix+testPreferredHelper)) | ||
| expected := defaultHelper | ||
| assert.Equal(t, expected, DetectDefaultStore("")) | ||
| }) | ||
|
|
||
| // Similarly, fall back to the default helper if the preferred credentials-helper | ||
| // is installed, but the helper binary isn't found. | ||
| t.Run("missing helper", func(t *testing.T) { | ||
| createFakeHelper(t, filepath.Join(tmpDir, testPreferredHelper)) | ||
| expected := defaultHelper | ||
| assert.Equal(t, expected, DetectDefaultStore("")) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| func createFakeHelper(t *testing.T, fileName string) { | ||
| t.Helper() | ||
| assert.NilError(t, os.WriteFile(fileName, []byte("I'm a credentials-helper executable (really!)"), 0o700)) | ||
| t.Cleanup(func() { | ||
| assert.NilError(t, os.RemoveAll(fileName)) | ||
| }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| package credentials | ||
|
|
||
| func defaultCredentialsStore() string { | ||
| return "wincred" | ||
| } | ||
| const ( | ||
| preferredHelper = "" | ||
| defaultHelper = "wincred" | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we testing for
defaultHelper's existence, but notpreferred's?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind, I see that the test for the preferred helper is inside
findPreferredHelper. I find this a bit hard to read, maybe because it mixes levels of abstraction. Maybe instead we could do something like