fix(daemon): preserve envfile auth provenance

This commit is contained in:
Peter Steinberger
2026-03-08 00:56:50 +00:00
parent ad052d661b
commit a2cb80b9c4
7 changed files with 120 additions and 12 deletions

View File

@@ -39,6 +39,15 @@ vi.mock("../daemon/runtime-paths.js", () => ({
vi.mock("../daemon/service-audit.js", () => ({
auditGatewayServiceConfig: mocks.auditGatewayServiceConfig,
needsNodeRuntimeMigration: vi.fn(() => false),
readEmbeddedGatewayToken: (
command: {
environment?: Record<string, string>;
environmentValueSources?: Record<string, "inline" | "file">;
} | null,
) =>
command?.environmentValueSources?.OPENCLAW_GATEWAY_TOKEN === "file"
? undefined
: command?.environment?.OPENCLAW_GATEWAY_TOKEN?.trim() || undefined,
SERVICE_AUDIT_CODES: {
gatewayEntrypointMismatch: "gateway-entrypoint-mismatch",
},
@@ -299,6 +308,49 @@ describe("maybeRepairGatewayServiceConfig", () => {
},
);
});
it("does not persist EnvironmentFile-backed service tokens into config", async () => {
await withEnvAsync(
{
OPENCLAW_GATEWAY_TOKEN: undefined,
CLAWDBOT_GATEWAY_TOKEN: undefined,
},
async () => {
mocks.readCommand.mockResolvedValue({
programArguments: gatewayProgramArguments,
environment: {
OPENCLAW_GATEWAY_TOKEN: "env-file-token",
},
environmentValueSources: {
OPENCLAW_GATEWAY_TOKEN: "file",
},
});
mocks.auditGatewayServiceConfig.mockResolvedValue({
ok: false,
issues: [],
});
mocks.buildGatewayInstallPlan.mockResolvedValue({
programArguments: gatewayProgramArguments,
workingDirectory: "/tmp",
environment: {},
});
mocks.install.mockResolvedValue(undefined);
const cfg: OpenClawConfig = {
gateway: {},
};
await runRepair(cfg);
expect(mocks.writeConfigFile).not.toHaveBeenCalled();
expect(mocks.buildGatewayInstallPlan).toHaveBeenCalledWith(
expect.objectContaining({
config: cfg,
}),
);
},
);
});
});
describe("maybeScanExtraGatewayServices", () => {

View File

@@ -15,6 +15,7 @@ import { renderSystemNodeWarning, resolveSystemNodeInfo } from "../daemon/runtim
import {
auditGatewayServiceConfig,
needsNodeRuntimeMigration,
readEmbeddedGatewayToken,
SERVICE_AUDIT_CODES,
} from "../daemon/service-audit.js";
import { resolveGatewayService } from "../daemon/service.js";
@@ -230,7 +231,7 @@ export async function maybeRepairGatewayServiceConfig(
command,
expectedGatewayToken,
});
const serviceToken = command.environment?.OPENCLAW_GATEWAY_TOKEN?.trim();
const serviceToken = readEmbeddedGatewayToken(command);
if (tokenRefConfigured && serviceToken) {
audit.issues.push({
code: SERVICE_AUDIT_CODES.gatewayTokenMismatch,
@@ -316,7 +317,7 @@ export async function maybeRepairGatewayServiceConfig(
if (!repair) {
return;
}
const serviceEmbeddedToken = command.environment?.OPENCLAW_GATEWAY_TOKEN?.trim() || undefined;
const serviceEmbeddedToken = readEmbeddedGatewayToken(command);
const gatewayTokenForRepair = expectedGatewayToken ?? serviceEmbeddedToken;
const configuredGatewayToken =
typeof cfg.gateway?.auth?.token === "string"