fix(doctor): warn when OPENCLAW_GATEWAY_TOKEN env overrides gateway.auth.token config (#74433)

* fix(doctor): warn when OPENCLAW_GATEWAY_TOKEN env overrides gateway.auth.token config (#74271)

* fix(doctor): narrow gateway token source warning

* test(status): type env secret provider fixture

* fix(doctor): scope gateway token conflict warning to local mode

Signed-off-by: sallyom <somalley@redhat.com>

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: sallyom <somalley@redhat.com>
This commit is contained in:
Logan Ye
2026-05-06 02:54:15 +08:00
committed by GitHub
parent 64b1f5fbf4
commit 7dc6007aee
8 changed files with 245 additions and 1 deletions

View File

@@ -2,6 +2,7 @@ import { isIP } from "node:net";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { hasConfiguredSecretInput } from "../config/types.secrets.js";
import { resolveGatewayAuth } from "../gateway/auth-resolve.js";
import { resolveGatewayAuthTokenSourceConflict } from "../gateway/auth-token-source-conflict.js";
import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalLowercaseString,
@@ -116,6 +117,17 @@ export function collectGatewayConfigFindings(
});
}
const tokenConflict = resolveGatewayAuthTokenSourceConflict({ cfg: sourceConfig, env });
if (tokenConflict) {
findings.push({
checkId: tokenConflict.checkId,
severity: "warn",
title: tokenConflict.title,
detail: tokenConflict.detail,
remediation: tokenConflict.remediation,
});
}
if (bind === "loopback" && controlUiEnabled && trustedProxies.length === 0) {
findings.push({
checkId: "gateway.trusted_proxies_missing",

View File

@@ -111,4 +111,42 @@ describe("security audit gateway config findings", () => {
})(),
]);
});
it("warns when OPENCLAW_GATEWAY_TOKEN shadows a different configured token source", async () => {
const cfg: OpenClawConfig = {
gateway: { auth: { token: "config-token" } },
};
const findings = collectGatewayConfigFindings(cfg, cfg, {
OPENCLAW_GATEWAY_TOKEN: "env-token",
});
expect(hasFinding("gateway.env_token_overrides_config", findings)).toBe(true);
});
it("does not warn when gateway.auth.token resolves from OPENCLAW_GATEWAY_TOKEN", async () => {
const cfg: OpenClawConfig = {
gateway: { auth: { token: "${OPENCLAW_GATEWAY_TOKEN}" } },
secrets: { providers: { default: { source: "env" } } },
};
const findings = collectGatewayConfigFindings(cfg, cfg, {
OPENCLAW_GATEWAY_TOKEN: "env-token",
});
expect(hasFinding("gateway.env_token_overrides_config", findings)).toBe(false);
});
it("does not warn about local gateway auth token precedence in remote mode", async () => {
const cfg: OpenClawConfig = {
gateway: {
mode: "remote",
remote: { token: "remote-token" },
auth: { token: "local-token" },
},
};
const findings = collectGatewayConfigFindings(cfg, cfg, {
OPENCLAW_GATEWAY_TOKEN: "env-token",
});
expect(hasFinding("gateway.env_token_overrides_config", findings)).toBe(false);
});
});