detached 340fd86

fix(app,test): align auth config semantics and stabilize resolver tests

Use cfg.Auth.Enabled when building auth.Config, update fail-closed allowlist log wording, and add regression coverage. Also restore package-level remote flags in resolver tests and document expected 503 fail-closed admin behavior in handler tests.
commit
340fd86d623223e7f013f91bbecd23b1e5edb2b5
author
brice · · 2026-02-09 06:43 UTC
parent
9b0b996
signature
unsigned
4 files · +42 -2
M internal/adapters/in/cli/controlplane_resolver_test.go +12 -0
@@ -12,6 +12,12 @@ func TestResolveControlPlane_LocalDeniedWhenAuthEnabled(t *testing.T) {
1212 t.Setenv("XDG_CONFIG_HOME", filepath.Join(tmpDir, "xdg"))
1313 t.Setenv("GORDON_REMOTE", "")
1414 t.Setenv("GORDON_TOKEN", "")
15+ originalRemoteFlag, originalTokenFlag, originalInsecureTLSFlag := remoteFlag, tokenFlag, insecureTLSFlag
16+ t.Cleanup(func() {
17+ remoteFlag = originalRemoteFlag
18+ tokenFlag = originalTokenFlag
19+ insecureTLSFlag = originalInsecureTLSFlag
20+ })
1521
1622 remoteFlag = ""
1723 tokenFlag = ""
@@ -46,6 +52,12 @@ func TestResolveControlPlane_LocalAllowedWhenAuthDisabled(t *testing.T) {
4652 t.Setenv("XDG_CONFIG_HOME", filepath.Join(tmpDir, "xdg"))
4753 t.Setenv("GORDON_REMOTE", "")
4854 t.Setenv("GORDON_TOKEN", "")
55+ originalRemoteFlag, originalTokenFlag, originalInsecureTLSFlag := remoteFlag, tokenFlag, insecureTLSFlag
56+ t.Cleanup(func() {
57+ remoteFlag = originalRemoteFlag
58+ tokenFlag = originalTokenFlag
59+ insecureTLSFlag = originalInsecureTLSFlag
60+ })
4961
5062 remoteFlag = ""
5163 tokenFlag = ""
@@ -12,6 +12,12 @@ func TestResolveControlPlane_LocalDeniedWhenAuthEnabled(t *testing.T) {
12 t.Setenv("XDG_CONFIG_HOME", filepath.Join(tmpDir, "xdg"))12 t.Setenv("XDG_CONFIG_HOME", filepath.Join(tmpDir, "xdg"))
13 t.Setenv("GORDON_REMOTE", "")13 t.Setenv("GORDON_REMOTE", "")
14 t.Setenv("GORDON_TOKEN", "")14 t.Setenv("GORDON_TOKEN", "")
15+ originalRemoteFlag, originalTokenFlag, originalInsecureTLSFlag := remoteFlag, tokenFlag, insecureTLSFlag
16+ t.Cleanup(func() {
17+ remoteFlag = originalRemoteFlag
18+ tokenFlag = originalTokenFlag
19+ insecureTLSFlag = originalInsecureTLSFlag
20+ })
15 21
16 remoteFlag = ""22 remoteFlag = ""
17 tokenFlag = ""23 tokenFlag = ""
@@ -46,6 +52,12 @@ func TestResolveControlPlane_LocalAllowedWhenAuthDisabled(t *testing.T) {
46 t.Setenv("XDG_CONFIG_HOME", filepath.Join(tmpDir, "xdg"))52 t.Setenv("XDG_CONFIG_HOME", filepath.Join(tmpDir, "xdg"))
47 t.Setenv("GORDON_REMOTE", "")53 t.Setenv("GORDON_REMOTE", "")
48 t.Setenv("GORDON_TOKEN", "")54 t.Setenv("GORDON_TOKEN", "")
55+ originalRemoteFlag, originalTokenFlag, originalInsecureTLSFlag := remoteFlag, tokenFlag, insecureTLSFlag
56+ t.Cleanup(func() {
57+ remoteFlag = originalRemoteFlag
58+ tokenFlag = originalTokenFlag
59+ insecureTLSFlag = originalInsecureTLSFlag
60+ })
49 61
50 remoteFlag = ""62 remoteFlag = ""
51 tokenFlag = ""63 tokenFlag = ""
M internal/app/run.go +2 -2
@@ -876,7 +876,7 @@ func createTokenStore(backend domain.SecretsBackend, dataDir string, log zerowra
876876
877877 func buildAuthConfig(ctx context.Context, cfg Config, authType domain.AuthType, backend domain.SecretsBackend, dataDir string, log zerowrap.Logger) (auth.Config, error) {
878878 authConfig := auth.Config{
879- Enabled: true,
879+ Enabled: cfg.Auth.Enabled,
880880 AuthType: authType,
881881 Username: cfg.Auth.Username,
882882 }
@@ -1380,7 +1380,7 @@ func buildRegistryCIDRAllowlistMiddleware(cfg Config, trustedNets []*net.IPNet,
13801380 if len(allowedNets) == 0 {
13811381 log.Error().
13821382 Strs("registry_allowed_ips", cfg.Server.RegistryAllowedIPs).
1383- Msg("registry_allowed_ips is set but no valid entries were parsed; registry will allow all traffic")
1383+ Msg("registry_allowed_ips is set but no valid entries were parsed; registry will deny all traffic (fail-closed)")
13841384 return func(next http.Handler) http.Handler {
13851385 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
13861386 log.Warn().
@@ -876,7 +876,7 @@ func createTokenStore(backend domain.SecretsBackend, dataDir string, log zerowra
876 876
877 func buildAuthConfig(ctx context.Context, cfg Config, authType domain.AuthType, backend domain.SecretsBackend, dataDir string, log zerowrap.Logger) (auth.Config, error) {877 func buildAuthConfig(ctx context.Context, cfg Config, authType domain.AuthType, backend domain.SecretsBackend, dataDir string, log zerowrap.Logger) (auth.Config, error) {
878 authConfig := auth.Config{878 authConfig := auth.Config{
879- Enabled: true,879+ Enabled: cfg.Auth.Enabled,
880 AuthType: authType,880 AuthType: authType,
881 Username: cfg.Auth.Username,881 Username: cfg.Auth.Username,
882 }882 }
@@ -1380,7 +1380,7 @@ func buildRegistryCIDRAllowlistMiddleware(cfg Config, trustedNets []*net.IPNet,
1380 if len(allowedNets) == 0 {1380 if len(allowedNets) == 0 {
1381 log.Error().1381 log.Error().
1382 Strs("registry_allowed_ips", cfg.Server.RegistryAllowedIPs).1382 Strs("registry_allowed_ips", cfg.Server.RegistryAllowedIPs).
1383- Msg("registry_allowed_ips is set but no valid entries were parsed; registry will allow all traffic")1383+ Msg("registry_allowed_ips is set but no valid entries were parsed; registry will deny all traffic (fail-closed)")
1384 return func(next http.Handler) http.Handler {1384 return func(next http.Handler) http.Handler {
1385 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {1385 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1386 log.Warn().1386 log.Warn().
A internal/app/run_auth_config_test.go +25 -0
@@ -0,0 +1,25 @@
1+package app
2+
3+import (
4+ "context"
5+ "testing"
6+
7+ "github.com/bnema/gordon/internal/domain"
8+ "github.com/bnema/zerowrap"
9+)
10+
11+func TestBuildAuthConfig_UsesConfigEnabledFlag(t *testing.T) {
12+ t.Setenv(TokenSecretEnvVar, "test-token-secret")
13+
14+ cfg := Config{}
15+ cfg.Auth.Enabled = false
16+ cfg.Auth.Type = "token"
17+
18+ authCfg, err := buildAuthConfig(context.Background(), cfg, domain.AuthTypeToken, domain.SecretsBackendUnsafe, t.TempDir(), zerowrap.Default())
19+ if err != nil {
20+ t.Fatalf("expected no error, got %v", err)
21+ }
22+ if authCfg.Enabled {
23+ t.Fatalf("expected auth config enabled=false, got true")
24+ }
25+}
@@ -0,0 +1,25 @@
1+package app
2+
3+import (
4+ "context"
5+ "testing"
6+
7+ "github.com/bnema/gordon/internal/domain"
8+ "github.com/bnema/zerowrap"
9+)
10+
11+func TestBuildAuthConfig_UsesConfigEnabledFlag(t *testing.T) {
12+ t.Setenv(TokenSecretEnvVar, "test-token-secret")
13+
14+ cfg := Config{}
15+ cfg.Auth.Enabled = false
16+ cfg.Auth.Type = "token"
17+
18+ authCfg, err := buildAuthConfig(context.Background(), cfg, domain.AuthTypeToken, domain.SecretsBackendUnsafe, t.TempDir(), zerowrap.Default())
19+ if err != nil {
20+ t.Fatalf("expected no error, got %v", err)
21+ }
22+ if authCfg.Enabled {
23+ t.Fatalf("expected auth config enabled=false, got true")
24+ }
25+}
M internal/app/run_http_handlers_test.go +3 -0
@@ -76,6 +76,9 @@ func TestCreateHTTPHandlers_AuthEnabled_ExposesAdminOnProxyForRegistryHost(t *te
7676
7777 svc := &services{adminHandler: &adminhttp.Handler{}}
7878 _, proxyHandler := createHTTPHandlers(svc, cfg, zerowrap.Default())
79+ // services uses an adminHandler stub with authSvc left nil. In createHTTPHandlers,
80+ // registerAdminRoutes installs fail-closed middleware for that case, so admin
81+ // requests on the allowed host return 503 ServiceUnavailable.
7982
8083 req := httptest.NewRequest(http.MethodGet, "/admin/status", nil)
8184 req.Host = "gordon.local"
@@ -76,6 +76,9 @@ func TestCreateHTTPHandlers_AuthEnabled_ExposesAdminOnProxyForRegistryHost(t *te
76 76
77 svc := &services{adminHandler: &adminhttp.Handler{}}77 svc := &services{adminHandler: &adminhttp.Handler{}}
78 _, proxyHandler := createHTTPHandlers(svc, cfg, zerowrap.Default())78 _, proxyHandler := createHTTPHandlers(svc, cfg, zerowrap.Default())
79+ // services uses an adminHandler stub with authSvc left nil. In createHTTPHandlers,
80+ // registerAdminRoutes installs fail-closed middleware for that case, so admin
81+ // requests on the allowed host return 503 ServiceUnavailable.
79 82
80 req := httptest.NewRequest(http.MethodGet, "/admin/status", nil)83 req := httptest.NewRequest(http.MethodGet, "/admin/status", nil)
81 req.Host = "gordon.local"84 req.Host = "gordon.local"

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close