test: cover trusted-proxy secret surfaces

This commit is contained in:
Peter Steinberger
2026-04-27 22:06:06 +01:00
parent 1a98938479
commit 7975305a89
5 changed files with 80 additions and 4 deletions

View File

@@ -139,7 +139,8 @@ export function createGatewayCredentialPlan(params: {
gateway?.tailscale?.mode === "serve" || gateway?.tailscale?.mode === "funnel";
const remoteConfiguredSurface = remoteMode || remoteUrlConfigured || tailscaleRemoteExposure;
const remoteTokenFallbackActive = localTokenCanWin && !envToken && !localToken.configured;
const remotePasswordFallbackActive = !envPassword && !localPassword.configured && passwordCanWin;
const remotePasswordFallbackActive =
authMode !== "trusted-proxy" && !envPassword && !localPassword.configured && passwordCanWin;
return {
configuredMode: gateway?.mode === "remote" ? "remote" : "local",

View File

@@ -309,6 +309,28 @@ describe("resolveGatewayCredentialsFromConfig", () => {
});
});
it("does not use remote password as trusted-proxy local fallback", () => {
const resolved = resolveGatewayCredentialsFromConfig({
cfg: cfg({
gateway: {
mode: "local",
auth: {
mode: "trusted-proxy",
},
remote: {
password: "remote-password", // pragma: allowlist secret
},
},
}),
env: {} as NodeJS.ProcessEnv,
});
expect(resolved).toEqual({
token: undefined,
password: undefined,
});
});
it("keeps local credentials ahead of remote fallback in local mode", () => {
const resolved = resolveGatewayCredentialsFromConfig({
cfg: cfg({

View File

@@ -110,7 +110,9 @@ function resolveLocalGatewayCredentials(params: {
: params.plan.remoteToken.value;
const fallbackPassword = params.plan.localPassword.configured
? params.plan.localPassword.value
: params.plan.remotePassword.value;
: params.plan.authMode === "trusted-proxy"
? undefined
: params.plan.remotePassword.value;
const localResolved = resolveGatewayCredentialsFromValues({
configToken: fallbackToken,
configPassword: fallbackPassword,

View File

@@ -87,6 +87,23 @@ describe("evaluateGatewayAuthSurfaceStates", () => {
});
});
it("marks gateway.auth.password active when trusted-proxy mode is explicit", () => {
const states = evaluate({
gateway: {
auth: {
mode: "trusted-proxy",
password: envRef("GW_AUTH_PASSWORD"),
},
},
} as OpenClawConfig);
expect(states["gateway.auth.password"]).toMatchObject({
hasSecretRef: true,
active: true,
reason: "no token source can win, so password auth can win.",
});
});
it("marks gateway.auth.password inactive when env token is configured", () => {
const states = evaluate(
{
@@ -197,4 +214,24 @@ describe("evaluateGatewayAuthSurfaceStates", () => {
reason: 'password auth cannot win with gateway.auth.mode="token".',
});
});
it("marks gateway.remote.password inactive as a trusted-proxy local fallback", () => {
const states = evaluate({
gateway: {
mode: "local",
auth: {
mode: "trusted-proxy",
},
remote: {
password: envRef("GW_REMOTE_PASSWORD"),
},
},
} as OpenClawConfig);
expect(states["gateway.remote.password"]).toMatchObject({
hasSecretRef: true,
active: false,
reason: "remote password fallback is not active.",
});
});
});

View File

@@ -19,6 +19,20 @@ async function expectInactiveGatewayPassword(config: unknown): Promise<void> {
expect(snapshot.warnings.map((warning) => warning.path)).toContain("gateway.auth.password");
}
async function expectActiveGatewayPassword(config: unknown): Promise<void> {
const snapshot = await prepareSecretsRuntimeSnapshot({
config: asConfig(config),
env: {
GATEWAY_PASSWORD_REF: "resolved-gateway-password",
},
agentDirs: ["/tmp/openclaw-agent-main"],
loadAuthStore: () => ({ version: 1, profiles: {} }),
});
expect(snapshot.config.gateway?.auth?.password).toBe("resolved-gateway-password");
expect(snapshot.warnings.map((warning) => warning.path)).not.toContain("gateway.auth.password");
}
describe("secrets runtime gateway local surfaces", () => {
it("treats gateway.remote refs as inactive when local auth credentials are configured", async () => {
const snapshot = await prepareSecretsRuntimeSnapshot({
@@ -139,8 +153,8 @@ describe("secrets runtime gateway local surfaces", () => {
).rejects.toThrow(/MISSING_GATEWAY_TOKEN_REF/);
});
it("treats gateway.auth.password ref as inactive when auth mode is trusted-proxy", async () => {
await expectInactiveGatewayPassword({
it("treats gateway.auth.password ref as active when auth mode is trusted-proxy", async () => {
await expectActiveGatewayPassword({
gateway: {
auth: {
mode: "trusted-proxy",