fix(gateway): fail closed on missing mode

This commit is contained in:
Peter Steinberger 2026-04-03 19:48:46 +09:00
parent a6649201b7
commit 2c7eea8f10
No known key found for this signature in database
5 changed files with 10 additions and 11 deletions

View File

@ -36,6 +36,7 @@ openclaw gateway run
Notes:
- By default, the Gateway refuses to start unless `gateway.mode=local` is set in `~/.openclaw/openclaw.json`. Use `--allow-unconfigured` for ad-hoc/dev runs.
- `openclaw onboard --mode local` and `openclaw setup` are expected to write `gateway.mode=local`. If the file exists but `gateway.mode` is missing, treat that as a broken or clobbered config and repair it instead of assuming local mode implicitly.
- Binding beyond loopback without auth is blocked (safety guardrail).
- `SIGUSR1` triggers an in-process restart when authorized (`commands.restart` is enabled by default; set `commands.restart: false` to block manual restart, while gateway tool/config apply/update remain allowed).
- `SIGINT`/`SIGTERM` handlers stop the gateway process, but they dont restore any custom terminal state. If you wrap the CLI with a TUI or raw-mode input, restore the terminal before exit.

View File

@ -82,6 +82,7 @@ Gateway token options in non-interactive mode:
- With `--install-daemon`, when token auth requires a token, SecretRef-managed gateway tokens are validated but not persisted as resolved plaintext in supervisor service environment metadata.
- With `--install-daemon`, if token mode requires a token and the configured token SecretRef is unresolved, onboarding fails closed with remediation guidance.
- With `--install-daemon`, if both `gateway.auth.token` and `gateway.auth.password` are configured and `gateway.auth.mode` is unset, onboarding blocks install until mode is set explicitly.
- Local onboarding writes `gateway.mode="local"` into the config. If a later config file is missing `gateway.mode`, treat that as config damage or an incomplete manual edit, not as a valid local-mode shortcut.
Example:

View File

@ -170,7 +170,7 @@ Look for:
Common signatures:
- `Gateway start blocked: set gateway.mode=local` → local gateway mode is not enabled. Fix: set `gateway.mode="local"` in your config (or run `openclaw configure`). If you are running OpenClaw via Podman, the default config path is `~/.openclaw/openclaw.json`.
- `Gateway start blocked: set gateway.mode=local` → local gateway mode is not enabled, or the config file was clobbered and lost `gateway.mode`. Fix: set `gateway.mode="local"` in your config, or re-run `openclaw onboard --mode local` / `openclaw setup` to restamp the expected local-mode config. If you are running OpenClaw via Podman, the default config path is `~/.openclaw/openclaw.json`.
- `refusing to bind gateway ... without auth` → non-loopback bind without token/password.
- `another gateway instance is already listening` / `EADDRINUSE` → port conflict.

View File

@ -207,7 +207,7 @@ describe("gateway run option collisions", () => {
);
});
it("defaults to local when snapshot is valid but has no gateway.mode", async () => {
it("blocks startup when the observed snapshot loses gateway.mode even if loadConfig still says local", async () => {
configState.cfg = {
gateway: {
mode: "local",
@ -224,10 +224,12 @@ describe("gateway run option collisions", () => {
},
};
// Should NOT block — gateway.mode defaults to "local" when unset (#54801)
await runGatewayCli(["gateway", "run"]);
await expect(runGatewayCli(["gateway", "run"])).rejects.toThrow("__exit__:1");
expect(startGatewayServer).toHaveBeenCalled();
expect(runtimeErrors).toContain(
"Gateway start blocked: set gateway.mode=local (current: unset) or pass --allow-unconfigured.",
);
expect(startGatewayServer).not.toHaveBeenCalled();
});
it.each(["none", "trusted-proxy"] as const)("accepts --auth %s override", async (mode) => {

View File

@ -348,12 +348,7 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
const configExists = snapshot?.exists ?? fs.existsSync(CONFIG_PATH);
const configAuditPath = path.join(resolveStateDir(process.env), "logs", "config-audit.jsonl");
const effectiveCfg = snapshot?.valid ? snapshot.config : cfg;
// Default to "local" when gateway.mode is unset. Prior to v2026.3.24 the
// gateway started without an explicit mode; the guard added in 3.24
// regressed startup on Windows (and other platforms) when the config file
// exists but doesn't contain gateway.mode — e.g. after `openclaw onboard`
// writes a minimal config. (#54801)
const mode = effectiveCfg.gateway?.mode ?? "local";
const mode = effectiveCfg.gateway?.mode;
if (!opts.allowUnconfigured && mode !== "local") {
if (!configExists) {
defaultRuntime.error(