Security: default gateway auth bootstrap and explicit mode none#20686
Security: default gateway auth bootstrap and explicit mode none#20686gumadeiras merged 9 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens Gateway startup authentication by making secure token auth the default when auth config is missing/unresolved, while reintroducing an explicit opt-out (gateway.auth.mode: "none") intended only for trusted loopback setups. It centralizes auth bootstrapping so both Gateway startup and browser control auth follow the same rules, and adjusts CLI override merging to avoid clobbering config with undefined.
Changes:
- Add shared startup auth bootstrap that auto-generates/persists
gateway.auth.tokenwhen needed, and reuse it across Gateway + browser control auth flows. - Change unresolved/missing gateway auth default from implicit open (
none) to secure (token), while supporting explicit configmode: "none"for loopback-only use. - Harden CLI/runtime auth+tailscale override merging and expand test coverage (unit + e2e) for the new behavior.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/gateway/startup-auth.ts | New helper to merge overrides safely and bootstrap/persist a missing token on startup. |
| src/gateway/startup-auth.test.ts | Unit tests covering token auto-generation/persistence and override merging behavior. |
| src/gateway/server.impl.ts | Invokes startup auth bootstrap early during server startup and logs when a token is generated. |
| src/gateway/server.auth.e2e.test.ts | Adds e2e coverage for explicit mode: "none" loopback connect behavior. |
| src/gateway/server-runtime-config.ts | Uses shared merge helpers to avoid undefined override clobbering. |
| src/gateway/server-runtime-config.test.ts | Adds runtime-config tests for explicit none-mode bind allow/deny matrix. |
| src/gateway/auth.ts | Defaults unresolved auth to token mode; authorizes mode: "none" explicitly. |
| src/gateway/auth.test.ts | Updates expectations for new default; adds tests for explicit none mode and authorize behavior. |
| src/config/zod-schema.ts | Extends config schema to allow gateway.auth.mode: "none". |
| src/config/types.gateway.ts | Extends GatewayAuthMode to include "none" and updates mode default docstring. |
| src/cli/gateway-cli/run.ts | Avoids passing undefined override fields; permits startup bootstrap path for token-without-token cases; warns on none mode. |
| src/cli/gateway-cli/run.option-collisions.test.ts | Adds regression test ensuring CLI can start in token mode without a configured token (bootstrap path). |
| src/browser/control-auth.ts | Reuses shared startup auth bootstrap; respects explicit none mode (no auto token generation). |
| src/browser/control-auth.test.ts | Adds test ensuring none mode doesn’t auto-generate a token. |
| src/browser/control-auth.auto-token.test.ts | Adds test ensuring auto-token logic respects explicit none mode. |
| docs/help/faq.md | Updates localhost token FAQ to reflect secure defaults + explicit none opt-out. |
| docs/gateway/configuration-reference.md | Documents auth.mode: "none" and updates inline mode list. |
| CHANGELOG.md | Adds fix note describing secure default + explicit none opt-out behavior. |
8202111 to
3201e5e
Compare
arosstale
left a comment
There was a problem hiding this comment.
The explicit mode separation (password/token/none instead of implicit empty-config = open) is the right direction — removes a large footgun class. The mergeGatewayAuthConfig shallow-merge pattern looks correct for runtime overrides. One edge case worth verifying: if mode: none is set but a token is also present in config, does resolveGatewayAuth treat mode as authoritative and ignore the token? Worth a test asserting mode: none + token: 'x' → unauthenticated.
mode takes precedence so if |
c10f70a to
47b6c28
Compare
47b6c28 to
be1b731
Compare
|
Merged via squash. Thanks @gumadeiras! |
…claw#20686) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: be1b731 Co-authored-by: gumadeiras <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
…claw#20686) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: be1b731 Co-authored-by: gumadeiras <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
…claw#20686) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: be1b731 Co-authored-by: gumadeiras <[email protected]> Co-authored-by: gumadeiras <[email protected]> Reviewed-by: @gumadeiras
Summary
tokenmode (no implicit fallback-to-open behavior)gateway.auth.tokenwhen missinggateway.auth.mode: "none"(manual config only)undefinedoverride fields that could clobber configured authmode: "none"and secure defaultsRoot Problem
The previous behavior mixed multiple auth defaults across codepaths and allowed implicit runtime states that diverged from setup/configure/doctor expectations. This created policy drift and unclear operator behavior.
Implementation Plan (executed)
mode: "none"support only when intentionally configuredKey Files
src/gateway/startup-auth.tssrc/gateway/server.impl.tssrc/browser/control-auth.tssrc/gateway/auth.tssrc/cli/gateway-cli/run.tssrc/config/types.gateway.tssrc/config/zod-schema.tsTests
pnpm checkpnpm vitest run src/gateway/auth.test.ts src/gateway/startup-auth.test.ts src/browser/control-auth.test.ts src/browser/control-auth.auto-token.test.ts src/gateway/server-runtime-config.test.ts src/cli/gateway-cli/run.option-collisions.test.tspnpm vitest run --config vitest.e2e.config.ts src/gateway/server.auth.e2e.test.tsNotes
mode: "none"loopback connect behavior in gateway auth e2e tests.Greptile Summary
This PR enhances gateway security by making token authentication the secure default while preserving explicit opt-out capability. The implementation centralizes auth bootstrap logic and eliminates implicit fallback-to-open behavior that previously created policy drift.
Key changes:
startup-auth.tswith auto-generation and persistence ofgateway.auth.tokenwhen missing"none"to"token"mode inauth.ts:198mode: "none"support for intentional open loopback setups (rejected for non-loopback binds)undefinedfields from clobbering configured auth via explicit merge logicThe change maintains strict bind/auth matrix validation - non-loopback binds still require authentication or explicit
trusted-proxymode, andmode: "none"is correctly rejected for non-loopback binds as shown in test coverage.Confidence Score: 5/5
mode: "none", undefined override handling, non-loopback bind validation, and integration with browser control auth. The changes are backwards-compatible for users with existing auth configuration while improving security for new deployments.Last reviewed commit: 7c1a7ee