Security: default gateway auth bootstrap and explicit mode none (#20686)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: be1b73182c
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
Gustavo Madeira Santana
2026-02-19 02:35:50 -05:00
committed by GitHub
parent a2e846f649
commit c5698caca3
18 changed files with 678 additions and 77 deletions

View File

@@ -98,6 +98,25 @@ describe("ensureBrowserControlAuth", () => {
expect(mocks.writeConfigFile).not.toHaveBeenCalled();
});
it("respects explicit none mode", async () => {
const cfg: OpenClawConfig = {
gateway: {
auth: {
mode: "none",
},
},
browser: {
enabled: true,
},
};
const result = await ensureBrowserControlAuth({ cfg, env: {} as NodeJS.ProcessEnv });
expect(result).toEqual({ auth: {} });
expect(mocks.loadConfig).not.toHaveBeenCalled();
expect(mocks.writeConfigFile).not.toHaveBeenCalled();
});
it("reuses auth from latest config snapshot", async () => {
const cfg: OpenClawConfig = {
browser: {

View File

@@ -49,6 +49,27 @@ describe("ensureBrowserControlAuth", () => {
});
});
describe("none mode", () => {
it("should not auto-generate token when auth mode is none", async () => {
const cfg: OpenClawConfig = {
gateway: {
auth: {
mode: "none",
},
},
};
const result = await ensureBrowserControlAuth({
cfg,
env: { OPENCLAW_BROWSER_AUTO_AUTH: "1" },
});
expect(result.generatedToken).toBeUndefined();
expect(result.auth.token).toBeUndefined();
expect(result.auth.password).toBeUndefined();
});
});
describe("token mode", () => {
it("should return existing token if configured", async () => {
const cfg: OpenClawConfig = {

View File

@@ -1,7 +1,7 @@
import crypto from "node:crypto";
import type { OpenClawConfig } from "../config/config.js";
import { loadConfig, writeConfigFile } from "../config/config.js";
import { loadConfig } from "../config/config.js";
import { resolveGatewayAuth } from "../gateway/auth.js";
import { ensureGatewayStartupAuth } from "../gateway/startup-auth.js";
export type BrowserControlAuth = {
token?: string;
@@ -58,6 +58,10 @@ export async function ensureBrowserControlAuth(params: {
return { auth };
}
if (params.cfg.gateway?.auth?.mode === "none") {
return { auth };
}
if (params.cfg.gateway?.auth?.mode === "trusted-proxy") {
return { auth };
}
@@ -71,25 +75,21 @@ export async function ensureBrowserControlAuth(params: {
if (latestCfg.gateway?.auth?.mode === "password") {
return { auth: latestAuth };
}
if (latestCfg.gateway?.auth?.mode === "none") {
return { auth: latestAuth };
}
if (latestCfg.gateway?.auth?.mode === "trusted-proxy") {
return { auth: latestAuth };
}
const generatedToken = crypto.randomBytes(24).toString("hex");
const nextCfg: OpenClawConfig = {
...latestCfg,
gateway: {
...latestCfg.gateway,
auth: {
...latestCfg.gateway?.auth,
mode: "token",
token: generatedToken,
},
},
};
await writeConfigFile(nextCfg);
const ensured = await ensureGatewayStartupAuth({
cfg: latestCfg,
env,
persist: true,
});
const ensuredAuth = resolveBrowserControlAuth(ensured.cfg, env);
return {
auth: { token: generatedToken },
generatedToken,
auth: ensuredAuth,
generatedToken: ensured.generatedToken,
};
}