1
0
mirror of https://github.com/docker/docker-credential-helpers.git synced 2026-06-28 15:21:29 +05:30

Compare commits

..

12 Commits

Author SHA1 Message Date
Albin Kerouanton cfd6d21216 Merge pull request #366 from thaJeztah/gha_bump_ubuntu
gha: add ubuntu 24.04, remove 20.04
2025-03-04 17:29:11 +01:00
Sebastiaan van Stijn ab29a6c87b gha: add ubuntu 24.04, remove 20.04
Github is phasing out Ubuntu 20.04, and currently is doing brownouts;
https://github.com/actions/runner-images/issues/11101

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-03-04 17:23:42 +01:00
Sebastiaan van Stijn 576efaa084 Merge pull request #363 from akerouanton/retract-v0.9.1
go.mod: retract v0.9.1
2025-03-04 17:21:35 +01:00
Sebastiaan van Stijn 9d6cdddf25 Merge pull request #364 from akerouanton/fix-regression-v0.9.0
osxkeychain: list: return full server URIs
2025-03-04 13:42:33 +01:00
Albin Kerouanton d8e34f8743 osxkeychain: tests: uncleaned paths are preserved
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-03-04 11:43:16 +01:00
Albin Kerouanton b1d5bf0326 osxkeychain: list: return full server URIs
Commit 4cdcdc2 changed the format of `list` output. Before that commit,
the json keys were containing full URIs (scheme://host/path[:port]),
but afterward, the keys were only containing the path component.

With this commit, the `list` operation now returns full URIs (fixing the
regression), and also fixes the malformed URIs issue when a port is
specified (introduced by 19ec1c3, and affecting >=v0.4.2,<v0.9.0).

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-03-04 11:20:57 +01:00
Albin Kerouanton 50b162c340 go.mod: retract v0.9.1
`osxkeychain` in v0.9.1 still doesn't list credentials as prior versions
did. We're retracting this version too.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-28 19:40:33 +01:00
Albin Kerouanton 833d2c334f Merge pull request #362 from akerouanton/retract-v0.9.0
go.mod: retract v0.9.0
2025-02-28 13:10:46 +01:00
Albin Kerouanton 9651bf7802 go.mod: retract v0.9.0
Commit 4cdcdc2 introduced two regressions in the `osxkeychain`
credential helper,  on `list` and `get` operations. These were addressed
in:

- Commit c7514a0: osxkeychain: list: do not error out when keychain is empty
- Commit f4cdabf: osxkeychain: store: use Apple's proto consts

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-28 13:05:40 +01:00
Sebastiaan van Stijn 26274da6cf Merge pull request #361 from akerouanton/fix-regressions-v0.9.0
[v0.9.0] osxkeychain: fix regressions on get and list
2025-02-28 12:51:02 +01:00
Albin Kerouanton f4cdabf916 osxkeychain: store: use Apple's proto consts
Commit 4cdcdc2 swapped consts `kSecProtocolTypeHTTPS` and
`kSecProtocolTypeHTTP` with plain-text "https" and "http" strings.

This is causing a regression where credentials stored with prior
versions (< v0.9.0) can't be fetched anymore.

Unfortunately we can't just revert back to using Objective-C consts, as
these are unsigned integers that need to be converted into `CFStringRef`
and then passed to an helper like `keychain.CFStringToString`.

Although `keychain.CFStringToString` is exported, it takes a C type
`C.CFStringRef` so it's not consumable from other packages due to Cgo
restrictions:

> Cgo translates C types into equivalent unexported Go types. Because
> the translations are unexported, a Go package should not expose C
> types in its exported API: a C type used in one Go package is
> different from the same C type used in another.

We could alternatively copy `keychain.CFStringToString` into the
`osxkeychain` package, but this commit takes a simpler approach: just
hardcode the value of `kSecProtocolTypeHTTPS` and `kSecProtocolTypeHTTP`
as strings. (These consts are very unlikely to ever change since it'd
break all existing consumers.)

This is **NOT** handling backward compatibility with v0.9.0, since it
was released only 12hrs ago. So this fix won't work with credentials
created with v0.9.0.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-28 12:19:53 +01:00
Albin Kerouanton c7514a0999 osxkeychain: list: do not error out when keychain is empty
Commit 4cdcdc2 replaced the in-tree Objective-C code with github.com/keybase/go-keychain
and inadvertently introduced a new failure mode on the `List` operation -
it now fails when the keychain is empty.

Before:

```
$ ./bin/build/docker-credential-osxkeychain list
{}
```

After:

```
$ ./bin/build/docker-credential-osxkeychain list
credentials not found in native keychain
```

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-28 10:00:35 +01:00
4 changed files with 102 additions and 21 deletions
+1 -1
View File
@@ -44,8 +44,8 @@ jobs:
fail-fast: false
matrix:
os:
- ubuntu-24.04
- ubuntu-22.04
- ubuntu-20.04
- macOS-15
- macOS-14
- macOS-13
+5
View File
@@ -2,6 +2,11 @@ module github.com/docker/docker-credential-helpers
go 1.21
retract (
v0.9.1 // osxkeychain: a regression caused backward-incompatibility with earlier versions
v0.9.0 // osxkeychain: a regression caused backward-incompatibility with earlier versions
)
require (
github.com/danieljoos/wincred v1.2.2
github.com/keybase/go-keychain v0.0.1
+25 -7
View File
@@ -12,6 +12,8 @@ import "C"
import (
"errors"
"net"
"net/url"
"strconv"
"github.com/docker/docker-credential-helpers/credentials"
@@ -117,28 +119,44 @@ func (h Osxkeychain) List() (map[string]string, error) {
default:
return nil, err
}
} else if len(res) == 0 {
return nil, credentials.NewErrCredentialsNotFound()
}
resp := make(map[string]string)
for _, r := range res {
if r.Path == "" {
continue
proto := "http"
if r.Protocol == kSecProtocolTypeHTTPS {
proto = "https"
}
resp[r.Path] = r.Account
host := r.Server
if r.Port != 0 {
host = net.JoinHostPort(host, strconv.Itoa(int(r.Port)))
}
u := url.URL{
Scheme: proto,
Host: host,
Path: r.Path,
}
resp[u.String()] = r.Account
}
return resp, nil
}
const (
// Hardcoded protocol types matching their Objective-C equivalents.
// https://developer.apple.com/documentation/security/ksecattrprotocolhttps?language=objc
kSecProtocolTypeHTTPS = "htps" // This is NOT a typo.
// https://developer.apple.com/documentation/security/ksecattrprotocolhttp?language=objc
kSecProtocolTypeHTTP = "http"
)
func splitServer(serverURL string, item keychain.Item) error {
u, err := registryurl.Parse(serverURL)
if err != nil {
return err
}
item.SetProtocol("https")
item.SetProtocol(kSecProtocolTypeHTTPS)
if u.Scheme == "http" {
item.SetProtocol("http")
item.SetProtocol(kSecProtocolTypeHTTP)
}
item.SetServer(u.Hostname())
if p := u.Port(); p != "" {
+71 -13
View File
@@ -15,11 +15,6 @@ func TestOSXKeychainHelper(t *testing.T) {
Username: "foobar",
Secret: "foobarbaz",
}
creds1 := &credentials.Credentials{
ServerURL: "https://foobar.example.com:2376/v2",
Username: "foobarbaz",
Secret: "foobar",
}
helper := Osxkeychain{}
if err := helper.Add(creds); err != nil {
t.Fatal(err)
@@ -43,19 +38,49 @@ func TestOSXKeychainHelper(t *testing.T) {
t.Fatal(err)
}
helper.Add(creds1)
defer helper.Delete(creds1.ServerURL)
newauths, err := helper.List()
if len(newauths)-len(auths) != 1 {
if err == nil {
t.Fatalf("Error: len(newauths): %d, len(auths): %d", len(newauths), len(auths))
}
t.Fatalf("Error: len(newauths): %d, len(auths): %d\n Error= %v", len(newauths), len(auths), err)
if _, ok := auths[creds.ServerURL]; !ok {
t.Fatalf("server %s not found in list, got: %+v", creds.ServerURL, auths)
}
// Insert another token and check if it is in the list
creds1 := &credentials.Credentials{
ServerURL: "https://foobar.example.com:2376/v2",
Username: "foobarbaz",
Secret: "foobar",
}
helper.Add(creds1)
defer helper.Delete(creds1.ServerURL)
auths, err = helper.List()
if err != nil {
t.Fatalf("operation List failed: %+v", err)
}
if _, ok := auths[creds.ServerURL]; !ok {
t.Fatalf("server %s not found in list, got: %+v", creds.ServerURL, auths)
}
if _, ok := auths[creds1.ServerURL]; !ok {
t.Fatalf("server %s not found in list, got: %+v", creds1.ServerURL, auths)
}
// Delete the 1st token inserted
if err := helper.Delete(creds.ServerURL); err != nil {
t.Fatal(err)
}
auths, err = helper.List()
if err != nil {
t.Fatalf("operation List failed: %+v", err)
}
// First token should have been deleted
if _, ok := auths[creds.ServerURL]; ok {
t.Fatalf("server %s was not deleted, got: %+v", creds.ServerURL, auths)
}
// Second token should still be there
if _, ok := auths[creds1.ServerURL]; !ok {
t.Fatalf("server %s not found in list, got: %+v", creds1.ServerURL, auths)
}
}
// TestOSXKeychainHelperRetrieveAliases verifies that secrets can be accessed
@@ -116,6 +141,39 @@ func TestOSXKeychainHelperRetrieveAliases(t *testing.T) {
}
}
func TestOSXKeychainHelperStoreWithUncleanPath(t *testing.T) {
helper := Osxkeychain{}
creds := &credentials.Credentials{
ServerURL: "https://::1:8080//////location/../../hello",
Username: "testuser",
Secret: "testsecret",
}
// Clean store before and after the test.
defer helper.Delete(creds.ServerURL)
if err := helper.Delete(creds.ServerURL); err != nil && !credentials.IsErrCredentialsNotFound(err) {
t.Errorf("prepare: failed to delete '%s': %v", creds.ServerURL, err)
}
// Store the credentials
if err := helper.Add(creds); err != nil {
t.Fatalf("Error: failed to store credentials with unclean path %q: %s", creds.ServerURL, err)
}
// Retrieve and verify credentials
username, secret, err := helper.Get(creds.ServerURL)
if err != nil {
t.Fatalf("Error: failed to retrieve credentials with unclean path %q: %s", creds.ServerURL, err)
}
if username != creds.Username {
t.Errorf("Error: expected username %s, got %s", creds.Username, username)
}
if secret != creds.Secret {
t.Errorf("Error: expected secret %s, got %s", creds.Secret, secret)
}
}
// TestOSXKeychainHelperRetrieveStrict verifies that only matching secrets are
// returned.
func TestOSXKeychainHelperRetrieveStrict(t *testing.T) {