test: cover trusted-proxy secret surfaces · openclaw/openclaw@7975305
steipete
·
2026-04-28
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -139,7 +139,8 @@ export function createGatewayCredentialPlan(params: {
|
139 | 139 | gateway?.tailscale?.mode === "serve" || gateway?.tailscale?.mode === "funnel"; |
140 | 140 | const remoteConfiguredSurface = remoteMode || remoteUrlConfigured || tailscaleRemoteExposure; |
141 | 141 | const remoteTokenFallbackActive = localTokenCanWin && !envToken && !localToken.configured; |
142 | | -const remotePasswordFallbackActive = !envPassword && !localPassword.configured && passwordCanWin; |
| 142 | +const remotePasswordFallbackActive = |
| 143 | +authMode !== "trusted-proxy" && !envPassword && !localPassword.configured && passwordCanWin; |
143 | 144 | |
144 | 145 | return { |
145 | 146 | configuredMode: gateway?.mode === "remote" ? "remote" : "local", |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -309,6 +309,28 @@ describe("resolveGatewayCredentialsFromConfig", () => {
|
309 | 309 | }); |
310 | 310 | }); |
311 | 311 | |
| 312 | +it("does not use remote password as trusted-proxy local fallback", () => { |
| 313 | +const resolved = resolveGatewayCredentialsFromConfig({ |
| 314 | +cfg: cfg({ |
| 315 | +gateway: { |
| 316 | +mode: "local", |
| 317 | +auth: { |
| 318 | +mode: "trusted-proxy", |
| 319 | +}, |
| 320 | +remote: { |
| 321 | +password: "remote-password", // pragma: allowlist secret |
| 322 | +}, |
| 323 | +}, |
| 324 | +}), |
| 325 | +env: {} as NodeJS.ProcessEnv, |
| 326 | +}); |
| 327 | + |
| 328 | +expect(resolved).toEqual({ |
| 329 | +token: undefined, |
| 330 | +password: undefined, |
| 331 | +}); |
| 332 | +}); |
| 333 | + |
312 | 334 | it("keeps local credentials ahead of remote fallback in local mode", () => { |
313 | 335 | const resolved = resolveGatewayCredentialsFromConfig({ |
314 | 336 | cfg: cfg({ |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -110,7 +110,9 @@ function resolveLocalGatewayCredentials(params: {
|
110 | 110 | : params.plan.remoteToken.value; |
111 | 111 | const fallbackPassword = params.plan.localPassword.configured |
112 | 112 | ? params.plan.localPassword.value |
113 | | - : params.plan.remotePassword.value; |
| 113 | + : params.plan.authMode === "trusted-proxy" |
| 114 | + ? undefined |
| 115 | + : params.plan.remotePassword.value; |
114 | 116 | const localResolved = resolveGatewayCredentialsFromValues({ |
115 | 117 | configToken: fallbackToken, |
116 | 118 | configPassword: fallbackPassword, |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -87,6 +87,23 @@ describe("evaluateGatewayAuthSurfaceStates", () => {
|
87 | 87 | }); |
88 | 88 | }); |
89 | 89 | |
| 90 | +it("marks gateway.auth.password active when trusted-proxy mode is explicit", () => { |
| 91 | +const states = evaluate({ |
| 92 | +gateway: { |
| 93 | +auth: { |
| 94 | +mode: "trusted-proxy", |
| 95 | +password: envRef("GW_AUTH_PASSWORD"), |
| 96 | +}, |
| 97 | +}, |
| 98 | +} as OpenClawConfig); |
| 99 | + |
| 100 | +expect(states["gateway.auth.password"]).toMatchObject({ |
| 101 | +hasSecretRef: true, |
| 102 | +active: true, |
| 103 | +reason: "no token source can win, so password auth can win.", |
| 104 | +}); |
| 105 | +}); |
| 106 | + |
90 | 107 | it("marks gateway.auth.password inactive when env token is configured", () => { |
91 | 108 | const states = evaluate( |
92 | 109 | { |
@@ -197,4 +214,24 @@ describe("evaluateGatewayAuthSurfaceStates", () => {
|
197 | 214 | reason: 'password auth cannot win with gateway.auth.mode="token".', |
198 | 215 | }); |
199 | 216 | }); |
| 217 | + |
| 218 | +it("marks gateway.remote.password inactive as a trusted-proxy local fallback", () => { |
| 219 | +const states = evaluate({ |
| 220 | +gateway: { |
| 221 | +mode: "local", |
| 222 | +auth: { |
| 223 | +mode: "trusted-proxy", |
| 224 | +}, |
| 225 | +remote: { |
| 226 | +password: envRef("GW_REMOTE_PASSWORD"), |
| 227 | +}, |
| 228 | +}, |
| 229 | +} as OpenClawConfig); |
| 230 | + |
| 231 | +expect(states["gateway.remote.password"]).toMatchObject({ |
| 232 | +hasSecretRef: true, |
| 233 | +active: false, |
| 234 | +reason: "remote password fallback is not active.", |
| 235 | +}); |
| 236 | +}); |
200 | 237 | }); |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -19,6 +19,20 @@ async function expectInactiveGatewayPassword(config: unknown): Promise<void> {
|
19 | 19 | expect(snapshot.warnings.map((warning) => warning.path)).toContain("gateway.auth.password"); |
20 | 20 | } |
21 | 21 | |
| 22 | +async function expectActiveGatewayPassword(config: unknown): Promise<void> { |
| 23 | +const snapshot = await prepareSecretsRuntimeSnapshot({ |
| 24 | +config: asConfig(config), |
| 25 | +env: { |
| 26 | +GATEWAY_PASSWORD_REF: "resolved-gateway-password", |
| 27 | +}, |
| 28 | +agentDirs: ["/tmp/openclaw-agent-main"], |
| 29 | +loadAuthStore: () => ({ version: 1, profiles: {} }), |
| 30 | +}); |
| 31 | + |
| 32 | +expect(snapshot.config.gateway?.auth?.password).toBe("resolved-gateway-password"); |
| 33 | +expect(snapshot.warnings.map((warning) => warning.path)).not.toContain("gateway.auth.password"); |
| 34 | +} |
| 35 | + |
22 | 36 | describe("secrets runtime gateway local surfaces", () => { |
23 | 37 | it("treats gateway.remote refs as inactive when local auth credentials are configured", async () => { |
24 | 38 | const snapshot = await prepareSecretsRuntimeSnapshot({ |
@@ -139,8 +153,8 @@ describe("secrets runtime gateway local surfaces", () => {
|
139 | 153 | ).rejects.toThrow(/MISSING_GATEWAY_TOKEN_REF/); |
140 | 154 | }); |
141 | 155 | |
142 | | -it("treats gateway.auth.password ref as inactive when auth mode is trusted-proxy", async () => { |
143 | | -await expectInactiveGatewayPassword({ |
| 156 | +it("treats gateway.auth.password ref as active when auth mode is trusted-proxy", async () => { |
| 157 | +await expectActiveGatewayPassword({ |
144 | 158 | gateway: { |
145 | 159 | auth: { |
146 | 160 | mode: "trusted-proxy", |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。