diff --git a/src/gateway/connection-auth.test.ts b/src/gateway/connection-auth.test.ts index 4b4d00e2cd5..f502d85f31b 100644 --- a/src/gateway/connection-auth.test.ts +++ b/src/gateway/connection-auth.test.ts @@ -343,4 +343,77 @@ describe("resolveGatewayConnectionAuth", () => { password: "config-first-password", // pragma: allowlist secret }); }); + + it("throws when config-first token SecretRef cannot resolve even if env token exists", async () => { + const config = cfg({ + gateway: { + mode: "local", + auth: { + token: { source: "env", provider: "default", id: "MISSING_CONFIG_FIRST_TOKEN" }, + }, + }, + secrets: { + providers: { + default: { source: "env" }, + }, + }, + }); + const env = { + OPENCLAW_GATEWAY_TOKEN: "env-token", + } as NodeJS.ProcessEnv; + + await expect( + resolveGatewayConnectionAuth({ + config, + env, + includeLegacyEnv: false, + localTokenPrecedence: "config-first", + }), + ).rejects.toThrow("gateway.auth.token"); + expect(() => + resolveGatewayConnectionAuthFromConfig({ + cfg: config, + env, + includeLegacyEnv: false, + localTokenPrecedence: "config-first", + }), + ).toThrow("gateway.auth.token"); + }); + + it("throws when config-first password SecretRef cannot resolve even if env password exists", async () => { + const config = cfg({ + gateway: { + mode: "local", + auth: { + mode: "password", + password: { source: "env", provider: "default", id: "MISSING_CONFIG_FIRST_PASSWORD" }, + }, + }, + secrets: { + providers: { + default: { source: "env" }, + }, + }, + }); + const env = { + OPENCLAW_GATEWAY_PASSWORD: "env-password", // pragma: allowlist secret + } as NodeJS.ProcessEnv; + + await expect( + resolveGatewayConnectionAuth({ + config, + env, + includeLegacyEnv: false, + localPasswordPrecedence: "config-first", + }), + ).rejects.toThrow("gateway.auth.password"); + expect(() => + resolveGatewayConnectionAuthFromConfig({ + cfg: config, + env, + includeLegacyEnv: false, + localPasswordPrecedence: "config-first", + }), + ).toThrow("gateway.auth.password"); + }); }); diff --git a/src/gateway/credentials.ts b/src/gateway/credentials.ts index 285ff95bef1..e48cd2b3b10 100644 --- a/src/gateway/credentials.ts +++ b/src/gateway/credentials.ts @@ -254,6 +254,24 @@ export function resolveGatewayCredentialsFromConfig(params: { authMode !== "none" && authMode !== "trusted-proxy" && !localResolved.password); + if ( + localTokenRef && + localTokenPrecedence === "config-first" && + !localToken && + Boolean(envToken) && + localTokenCanWin + ) { + throwUnresolvedGatewaySecretInput("gateway.auth.token"); + } + if ( + localPasswordRef && + localPasswordPrecedence === "config-first" && + !localPassword && + Boolean(envPassword) && + localPasswordCanWin + ) { + throwUnresolvedGatewaySecretInput("gateway.auth.password"); + } if (localTokenRef && !localResolved.token && !envToken && localTokenCanWin) { throwUnresolvedGatewaySecretInput("gateway.auth.token"); }