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:
Alano Terblanche committed 2026-10-21 16:29:13 +02:00
1 parent b04093e5f1
commit f8d412e7e6
9 files changed
+60 -78

No files matched your search

+1 -1
View File
@@ -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
}
+1 -10
View File
@@ -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()
+25 -9
View File
@@ -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...)
}
-36
View File
@@ -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 ""
}
+10
View File
@@ -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
}
+7
View File
@@ -0,0 +1,7 @@
//go:build !darwin && !linux && !windows
package desktop
import "testing"
func installNoSecretsEngine(*testing.T) {}
+16
View File
@@ -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()