mirror of
https://github.com/docker/docker-agent.git
synced 2026-11-04 10:02:15 +00:00
refactor(desktop): build the secrets engine only where the SDK does
Put secrets_engine.go behind the darwin/linux/windows build tag so it uses the SDK directly: ErrSecretsEngineNotRunning, ConnectError.Hint and the client constructor. This drops the errNoSecretsEngine, secretsEngineHint and newSecretsEngineHubAuth wrappers. Other platforms get a single secretsEngineToken stub that finds no token.
This commit is contained in:
9 files changed
+60
-78
No files matched your search
@@ -65,7 +65,7 @@ func GetTokenWithSource(ctx context.Context) (string, Source) {
|
||||
return token, source
|
||||
}
|
||||
|
||||
if token, ok := secretsEngineToken(ctx, defaultSecretsEngine()); ok {
|
||||
if token, ok := secretsEngineToken(ctx); ok {
|
||||
return token, SourceSecretsEngine
|
||||
}
|
||||
|
||||
|
||||
@@ -369,15 +369,6 @@ func TestGetUserInfo(t *testing.T) {
|
||||
assert.Equal(t, DockerHubInfo{Username: "claims-user", Email: "claims@example.com"}, GetUserInfo(t.Context()))
|
||||
})
|
||||
|
||||
t.Run("names the account of a secrets engine token", func(t *testing.T) {
|
||||
backend := &fakeBackend{token: makeIdentityToken(t, "claims-user", "claims@example.com")}
|
||||
backend.info = &desktopAccount
|
||||
installFakeBackend(t, backend)
|
||||
installFakeEngine(t, &fakeEngine{token: makeIdentityToken(t, "engine-user", "engine@example.com")})
|
||||
|
||||
assert.Equal(t, DockerHubInfo{Username: "engine-user", Email: "engine@example.com"}, GetUserInfo(t.Context()))
|
||||
})
|
||||
|
||||
t.Run("falls back to Docker Desktop for a token without an account", func(t *testing.T) {
|
||||
backend := &fakeBackend{token: makeToken(t, time.Now().Add(time.Hour))}
|
||||
backend.info = &desktopAccount
|
||||
@@ -526,7 +517,7 @@ func installFakeBackend(t *testing.T, backend *fakeBackend) {
|
||||
}
|
||||
t.Cleanup(func() { mintToken = oldMint })
|
||||
|
||||
installFakeEngine(t, &fakeEngine{})
|
||||
installNoSecretsEngine(t)
|
||||
|
||||
clearCache := func() {
|
||||
cache.Lock()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build darwin || linux || windows
|
||||
|
||||
package desktop
|
||||
|
||||
import (
|
||||
@@ -7,7 +9,11 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
secretsengine "github.com/docker/secrets-engine/client"
|
||||
"github.com/docker/secrets-engine/client/dockerhub"
|
||||
"github.com/docker/secrets-engine/x/api"
|
||||
|
||||
"github.com/docker/docker-agent/pkg/hubauth"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -26,10 +32,20 @@ var (
|
||||
const secretsEngineFailureMsg = "Could not read the Docker Hub session from the secrets engine"
|
||||
|
||||
// defaultSecretsEngine is the engine [GetTokenWithSource] reads, created on first use.
|
||||
var defaultSecretsEngine = sync.OnceValue(func() *secretsEngine {
|
||||
client, err := newSecretsEngineHubAuth()
|
||||
return &secretsEngine{client: client, clientErr: err, logger: slog.Default()}
|
||||
})
|
||||
var defaultSecretsEngine = sync.OnceValue(newSecretsEngine)
|
||||
|
||||
// newSecretsEngine connects to Docker Desktop's secrets engine, reading staging sessions on staging.
|
||||
func newSecretsEngine() *secretsEngine {
|
||||
client, err := secretsengine.New(secretsengine.WithSocketPath(api.DesktopSocketPath()))
|
||||
if err != nil {
|
||||
return &secretsEngine{clientErr: err, logger: slog.Default()}
|
||||
}
|
||||
var opts []dockerhub.Option
|
||||
if hubauth.Staging() {
|
||||
opts = append(opts, dockerhub.Staging())
|
||||
}
|
||||
return &secretsEngine{client: client.HubAuth(opts...), logger: slog.Default()}
|
||||
}
|
||||
|
||||
// secretsEngine reads Docker Hub sessions from the secrets engine, sharing lookups and cooling down after failures.
|
||||
type secretsEngine struct {
|
||||
@@ -51,8 +67,8 @@ type secretsEngineLookup struct {
|
||||
}
|
||||
|
||||
// secretsEngineToken returns a usable token from the secrets engine and caches it.
|
||||
func secretsEngineToken(ctx context.Context, engine *secretsEngine) (string, bool) {
|
||||
token, err := engine.fetch(ctx)
|
||||
func secretsEngineToken(ctx context.Context) (string, bool) {
|
||||
token, err := defaultSecretsEngine().fetch(ctx)
|
||||
switch {
|
||||
case err != nil:
|
||||
slog.DebugContext(ctx, "Skipping the secrets engine", "error", err)
|
||||
@@ -161,12 +177,12 @@ func (e *secretsEngine) session(ctx context.Context) (string, error) {
|
||||
// logError warns once per run of failures, except for a missing engine.
|
||||
func (e *secretsEngine) logError(ctx context.Context, err error) {
|
||||
level := slog.LevelWarn
|
||||
if errors.Is(err, errNoSecretsEngine) || e.failureReported() {
|
||||
if errors.Is(err, secretsengine.ErrSecretsEngineNotRunning) || e.failureReported() {
|
||||
level = slog.LevelDebug
|
||||
}
|
||||
args := []any{"error", err}
|
||||
if hint := secretsEngineHint(err); hint != "" {
|
||||
args = append(args, "hint", hint)
|
||||
if connErr, ok := errors.AsType[*secretsengine.ConnectError](err); ok && connErr.Hint() != "" {
|
||||
args = append(args, "hint", connErr.Hint())
|
||||
}
|
||||
e.logger.Log(ctx, level, secretsEngineFailureMsg, args...)
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
//go:build darwin || linux || windows
|
||||
|
||||
package desktop
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
secretsengine "github.com/docker/secrets-engine/client"
|
||||
"github.com/docker/secrets-engine/client/dockerhub"
|
||||
"github.com/docker/secrets-engine/x/api"
|
||||
|
||||
"github.com/docker/docker-agent/pkg/hubauth"
|
||||
)
|
||||
|
||||
// errNoSecretsEngine means nothing is listening on the engine socket.
|
||||
var errNoSecretsEngine = secretsengine.ErrSecretsEngineNotRunning
|
||||
|
||||
// newSecretsEngineHubAuth connects to Docker Desktop's secrets engine, reading staging sessions on staging.
|
||||
func newSecretsEngineHubAuth() (dockerhub.ClientAuth, error) {
|
||||
engine, err := secretsengine.New(secretsengine.WithSocketPath(api.DesktopSocketPath()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if hubauth.Staging() {
|
||||
return engine.HubAuth(dockerhub.Staging()), nil
|
||||
}
|
||||
return engine.HubAuth(), nil
|
||||
}
|
||||
|
||||
// secretsEngineHint returns the SDK's recovery hint for a failed connection, or "".
|
||||
func secretsEngineHint(err error) string {
|
||||
if connErr, ok := errors.AsType[*secretsengine.ConnectError](err); ok {
|
||||
return connErr.Hint()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
//go:build !darwin && !linux && !windows
|
||||
|
||||
package desktop
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/docker/secrets-engine/client/dockerhub"
|
||||
)
|
||||
|
||||
// errNoSecretsEngine means the SDK doesn't support this platform.
|
||||
var errNoSecretsEngine = errors.New("the secrets engine is not available on this platform")
|
||||
|
||||
// newSecretsEngineHubAuth always fails with errNoSecretsEngine.
|
||||
func newSecretsEngineHubAuth() (dockerhub.ClientAuth, error) {
|
||||
return nil, errNoSecretsEngine
|
||||
}
|
||||
|
||||
// secretsEngineHint returns "": there is no engine to connect to.
|
||||
func secretsEngineHint(error) string {
|
||||
return ""
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,10 @@
|
||||
//go:build !darwin && !linux && !windows
|
||||
|
||||
package desktop
|
||||
|
||||
import "context"
|
||||
|
||||
// secretsEngineToken never finds a token: the SDK doesn't support this platform.
|
||||
func secretsEngineToken(context.Context) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
//go:build !darwin && !linux && !windows
|
||||
|
||||
package desktop
|
||||
|
||||
import "testing"
|
||||
|
||||
func installNoSecretsEngine(*testing.T) {}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build darwin || linux || windows
|
||||
|
||||
package desktop
|
||||
|
||||
import (
|
||||
@@ -95,6 +97,15 @@ func TestGetTokenFromSecretsEngine(t *testing.T) {
|
||||
assert.Equal(t, 0, backend.refreshes())
|
||||
})
|
||||
|
||||
t.Run("GetUserInfo names the account of an engine token", func(t *testing.T) {
|
||||
backend := &fakeBackend{token: makeIdentityToken(t, "claims-user", "claims@example.com")}
|
||||
backend.info = &DockerHubInfo{Username: "desktop-user", Email: "desktop@example.com"}
|
||||
installFakeBackend(t, backend)
|
||||
installFakeEngine(t, &fakeEngine{token: makeIdentityToken(t, "engine-user", "engine@example.com")})
|
||||
|
||||
assert.Equal(t, DockerHubInfo{Username: "engine-user", Email: "engine@example.com"}, GetUserInfo(t.Context()))
|
||||
})
|
||||
|
||||
t.Run("a refused engine token is not served again", func(t *testing.T) {
|
||||
fromEngine := makeToken(t, time.Now().Add(time.Hour))
|
||||
fromDesktop := makeToken(t, time.Now().Add(time.Hour))
|
||||
@@ -304,6 +315,11 @@ func awaitLookup(engine *secretsEngine) {
|
||||
}
|
||||
}
|
||||
|
||||
func installNoSecretsEngine(t *testing.T) {
|
||||
t.Helper()
|
||||
installFakeEngine(t, &fakeEngine{})
|
||||
}
|
||||
|
||||
func installFakeEngine(t *testing.T, fake *fakeEngine) {
|
||||
t.Helper()
|
||||
|
||||
|
||||
Reference in new issue
Block a user