Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cli/command/registry/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ func runLogout(ctx context.Context, dockerCLI command.Cli, serverAddress string)
// the tries below are kept for backward compatibility where a user could have
// saved the registry in one of the following format.
regsToLogout = append(regsToLogout, hostnameAddress, "http://"+hostnameAddress, "https://"+hostnameAddress)
// Credentials for the default registry are stored under the full index
// address, which is the key "docker login docker.io" writes to. The
// hostnames below are the ones that getAuthConfigKey in
// cli/config/configfile maps to that key.
if hostnameAddress == registry.DefaultNamespace || hostnameAddress == registry.IndexHostname {
regsToLogout = append(regsToLogout, registry.IndexServer)
}
}

if isDefaultRegistry {
Expand Down
50 changes: 50 additions & 0 deletions cli/command/registry/logout_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package registry

import (
"context"
"path/filepath"
"testing"

"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)

// TestLogoutRemovesCredentialsStoredByLogin verifies that logging out with the
// same argument that was used to log in removes the stored credentials.
//
// Credentials for the default registry are stored under
// [registry.IndexServer] regardless of the spelling passed to "docker login",
// so logout has to look for that key as well to find them again.
func TestLogoutRemovesCredentialsStoredByLogin(t *testing.T) {
for _, serverAddress := range []string{
"",
"docker.io",
"index.docker.io",
"https://index.docker.io/v1/",
"myreg.example.com",
} {
name := serverAddress
if name == "" {
name = "no server address"
}
t.Run(name, func(t *testing.T) {
configFile := configfile.New(filepath.Join(t.TempDir(), "config.json"))
cli := test.NewFakeCli(&fakeClient{})
cli.SetConfigFile(configFile)

err := runLogin(context.Background(), cli, loginOptions{
serverAddress: serverAddress,
user: "my-username",
password: "my-password",
})
assert.NilError(t, err)
assert.Assert(t, is.Len(configFile.AuthConfigs, 1), "login did not store credentials")

err = runLogout(context.Background(), cli, serverAddress)
assert.NilError(t, err)
assert.Check(t, is.Len(configFile.AuthConfigs, 0))
})
}
}