fix(configure): mask gateway token input in CLI wizard prompt#91059
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 13, 2026, 7:28 PM ET / 23:28 UTC. Summary PR surface: Source +6, Tests +14. Total +20 across 4 files. Reproducibility: yes. Current main source routes the affected configure gateway token and password prompts through Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land one focused configure-gateway secret-prompt fix that masks both plaintext token and password input while preserving the actual stored secret values, then close or rebase the sibling password PR. Do we have a high-confidence way to reproduce the issue? Yes. Current main source routes the affected configure gateway token and password prompts through Is this the best way to solve the issue? Yes. The PR uses the existing Clack password prompt at the configure command boundary, keeps normalization and config persistence unchanged, and avoids adding a new config or migration path. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 47759c35063c. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +6, Tests +14. Total +20 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
fc5f145 to
0f5a9ac
Compare
There was a problem hiding this comment.
Thank you @vincentkoc for adding in the configure gateway password code checks! 👍🏼 💯
Feel free to close this PR which has the redundant checks for gateway password checks #90571
|
Maintainer verification for current head
Merging by squash. |
Summary
What problem does this PR solve?
The
openclaw configure --section gatewaywizard presents aGateway token (blank to generate)prompt usingclack text(), which echoes every typed character — and the auto-generated token — in cleartext on the terminal. Anyone running the wizard over a shared screen, screen recording, or pair-programming session can see the token.Why does this matter now?
This is the same class of UX/security defect fixed in #76693 (onboarding wizard) and #90571 (gateway password prompt). The
Gateway tokenprompt was the one remaining unmasked credential surface in theconfigure --section gatewayflow.What is the intended outcome?
The
Gateway token (blank to generate)prompt renders bullets (••••) instead of typed or auto-generated characters. The persisted value inopenclaw.jsonis the actual token string — masking is render-only, config behavior is unchanged.What is intentionally out of scope?
Gateway passwordprompt — addressed in sibling PR fix(configure): mask gateway password input in CLI wizard prompt #90571.paste-tokenauth prompt — addressed in sibling PR fix(models): mask paste-token input in CLI auth prompt #90893.What does success look like?
Running the published-CLI repro after this patch shows bullets where the before screenshots show cleartext. The
openclaw.jsongateway.auth.tokenfield holds the actual token string, not bullet characters.What should reviewers focus on?
passwordhelper inconfigure.shared.tsmatches the pattern of the existingtext/confirm/selectwrappers.passwordInputlocal-variable rename in theauthMode === "password"branch avoids shadowing the newly importedpasswordhelper (same rename PR fix(configure): mask gateway password input in CLI wizard prompt #90571 applies — both PRs are in-flight).configure.gateway.test.ts's existingtextQueuefixtures drive the token branch via the newpasswordmock without any fixture changes.Linked context
Which issue does this close?
None — this PR was authored from an audit of unmasked credential prompts, not in response to an open issue.
Which issues, PRs, or discussions are related?
Was this requested by a maintainer or owner?
No — found while auditing remaining unmasked credential prompts after #76693 merged.
Real behavior proof (required for external PRs)
openclaw configure --section gatewayechoes the Gateway token in cleartext — both typed tokens and the auto-generated hex token are visible on-screen.pnpm openclaw configure --section gateway.git checkout fix/gateway-token-cleartextpnpm install && pnpm buildpnpm openclaw configure --section gatewayGateway token (blank to generate)— type any string or press Enter; observe bullets••••Gateway token (blank to generate)prompt render as••••••••••. Thegateway.auth.tokenvalue inopenclaw.jsonis the actual token string (not bullets), confirming masking is render-only and config persistence is unaffected.@clack/promptscode with noprocess.platformbranching — the fix applies on all three platforms automatically. Verification on each is tracked as a separate atomic task — macOS: [verify] gateway token mask renders bullets on macOS (PR #91059) #91064; Linux: [verify] gateway token mask renders bullets on Linux (PR #91059) #91065.Tests and validation
Which commands did you run?
pnpm tsgo:corerun after each file edit — green each time.pnpm test:changed— one pre-existing failure insrc/crestodian/operations.test.ts(Windows POSIX-path hardcode/tmp/workvsE:\tmp\work) — not caused by this diff, perCONTRIBUTING.md:128-129. Full build green (all phases: tsdown, ui:build, runtime-postbuild).pnpm check— typecheck green;no-shadowlint error onpasswordresolved in this PR by renamingconst password → const passwordInputin theauthMode === "password"branch; pre-existing unrelated lint errors inextensions/device-pair/andscripts/not addressed perCONTRIBUTING.md:128-129. After fix commitfc5f145c0e:pnpm build✓;pnpm checktypecheck ✓ (4 pre-existing lint failures inextensions/device-pair/notify.ts+scripts/— unrelated);pnpm test:changed— 47/48 pass (1 pre-existing POSIX-path failure increstodian/operations.test.ts, unrelated).What regression coverage was added or updated?
Added
password: vi.fn()mock toconfigure.gateway.test.ts, wired through the existingtextQueueso all 11 tests continue to pass via the new mock path with no fixture changes. AddedclackPassword: vi.fn()andpassword: mocks.clackPasswordto the@clack/promptsmock insrc/commands/configure.wizard.test.tsso the shared module import chain resolves correctly (commitfc5f145c0e).What failed before this fix, if known?
No automated test failure — this is a TTY rendering defect not assertable by unit tests. The proof is the live terminal capture.
If no test was added, why not?
Automated tests cannot assert "the TTY renders bullets, not characters." The structural fix (swapping
text → password) is verified by the manual repro screenshots and by the mock wiring that confirms the prompt feeds the same config persistence path.Risk checklist
Did user-visible behavior change? (
Yes/No)Yes — the
Gateway token (blank to generate)prompt now renders bullets instead of characters. TheinitialValuepre-fill (which displayed the auto-generated token in the field before the user pressed Enter) is also removed, as@clack/promptspassword()does not acceptinitialValue. The blank-input fallback (normalizeGatewayTokenInput(tokenInput) || randomToken()) still auto-generates a token when the field is left blank.Did config, environment, or migration behavior change? (
Yes/No)No —
gateway.auth.tokeninopenclaw.jsonis persisted as the typed or auto-generated string, unchanged. No migration needed.Did security, auth, secrets, network, or tool execution behavior change? (
Yes/No)Yes — masking the on-screen rendering of token input. This is the intended security fix; no other auth/network behavior is altered.
What is the highest-risk area?
Dropping
initialValue: randomToken()changes the UX: the field no longer pre-fills with a generated token. Users who pressed Enter to accept the default will still get a generated token, but it won't be visible during entry. This is intentional — showing it would defeat the masking.How is that risk mitigated?
The "blank to generate" message communicates that blank input is valid. The generated token is stored in
openclaw.jsonimmediately after the wizard completes and is readable there. This is consistent with how all other credential prompts in the wizard behave after the#76693/#90571/#90893series of fixes.Current review state
What is the next action?
Maintainer review.
What is still waiting on author, maintainer, CI, or external proof?
check-lint,build-artifacts,check-test-types,check-additional-extension-bundled,check-additional-runtime-topology-architecture) are pre-existing main branch failures, confirmed by PR Fix Control UI CJK IME composition #91087 (independent feature, same failures listed verbatim in its body). Per CONTRIBUTING.md:128-129, these do not block this contributor PR.Which bot or reviewer comments were addressed?
ClawSweeper Codex review (2026-06-07, commit
079414a9): P1 finding addressed in commitfc5f145c0e— addedclackPassword: vi.fn()to thevi.hoisted()mocks andpassword: mocks.clackPasswordto thevi.mock("@clack/prompts", ...)block insrc/commands/configure.wizard.test.ts. Mirrors the sibling fix in PR #90571 (commitfa3f5e8aa4). Gate:pnpm build✓;pnpm checktypecheck ✓ (pre-existing lint failures inextensions/device-pair/andscripts/— unrelated);pnpm test:changed— 47/48 pass (1 pre-existing Windows POSIX-path failure increstodian/operations.test.ts).AI-assisted PR:
codex review --base origin/mainlocally and address the findings before asking for review