fix(auth): recover from malformed API-key profiles#97520
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 28, 2026, 2:03 PM ET / 18:03 UTC. Summary PR surface: Source +66, Tests +162. Total +228 across 12 files. Reproducibility: yes. at source level: current main accepts non-empty API-key input and treats stored API-key profiles as eligible by presence, while the linked issue shows an onboard command stored as the key. I did not run a live Z.AI credential request. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. 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: Have auth owners choose one canonical repair path, preserving valid static keys, SecretRef/keyRef handling, and env/config fallback while rejecting OpenClaw onboard command text before it is used as provider auth. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main accepts non-empty API-key input and treats stored API-key profiles as eligible by presence, while the linked issue shows an onboard command stored as the key. I did not run a live Z.AI credential request. Is this the best way to solve the issue? Mostly yes: a shared stored-credential eligibility guard is a maintainable root boundary for preventing command text from masquerading as auth. The unresolved decision is whether maintainers prefer this generic boundary or the related provider-owned path. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against a10add753189. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +66, Tests +162. Total +228 across 12 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
|
* fix: reject malformed API-key auth profiles * fix(auth): detect onboard command API-key variants * fix(auth): reject malformed API-key flags
* fix: reject malformed API-key auth profiles * fix(auth): detect onboard command API-key variants * fix(auth): reject malformed API-key flags (cherry picked from commit fb7e10e)
* fix: reject malformed API-key auth profiles * fix(auth): detect onboard command API-key variants * fix(auth): reject malformed API-key flags
* fix: reject malformed API-key auth profiles * fix(auth): detect onboard command API-key variants * fix(auth): reject malformed API-key flags
* fix: reject malformed API-key auth profiles * fix(auth): detect onboard command API-key variants * fix(auth): reject malformed API-key flags
* fix: reject malformed API-key auth profiles * fix(auth): detect onboard command API-key variants * fix(auth): reject malformed API-key flags (cherry picked from commit fb7e10e)
Closes #97313
Summary
Fixes an issue where Z.AI users could rotate credentials or run setup/doctor repair, but sub-agents and embedded model auth would still try a stale stored
zai:defaultauth profile whose API-key value was accidentally saved as anopenclaw onboard ... --auth-choice ...command. That made the bad profile look usable, so auth selection could prefer it over current env/config credentials and produce Z.AI 401s.return nullbranches are explicit fail-closed paths for malformed explicit profile and non-interactive flag inputs after emitting a user-facing diagnostic, so the caller stops before using command text as provider auth. Thereturn undefinedbranch in option handling preserves the existing “this option did not apply” contract for unmatched provider options and is not a fallback for malformed matching options. The test prompter cast stays local to the doctor-auth test fixture because the test only exercises the prompt methods used by that doctor path.Linked context
What Problem This Solves
Fixes an issue where users who accidentally saved an OpenClaw onboarding command as a Z.AI API key could still see sub-agent or embedded model auth use that stale stored profile after credential rotation or setup/doctor repair. The expected recovery path is that current env/config credentials can take over and doctor points to the malformed stored profile instead of letting it masquerade as usable auth.
zai:defaultprofile without deleting all auth state, and future setup/onboarding attempts reject the command text before it is stored or sent to provider endpoint detection.Why This Change Was Made
This treats command-shaped API-key profile values as malformed at the shared auth-profile eligibility boundary. Stored malformed profiles are skipped during provider auth selection and explicit profile resolution, doctor surfaces them as
missing [malformed_api_key], and provider setup/onboarding input validation rejects pasted onboarding commands before they can be persisted or used.--auth-choice, including documented non-interactive forms with intervening flags.openclaw onboard ... --auth-choice ...command is not a valid provider API key, and leaving it eligible causes the reported Z.AI 401 recovery failure; the detector deliberately stays narrower than general shell-command detection to avoid rejecting normal secrets.Compatibility/risk boundary: the new malformed check is intentionally narrow to OpenClaw onboarding command text containing
--auth-choice, including documented non-interactive forms where other flags appear before--auth-choice. It does not change normal API-key, token, OAuth, keyRef, or SecretRef handling. This PR keeps the behavior in shared auth-profile eligibility because the poisoned value is consumed by multiple paths: sub-agent auth selection, explicit profile lookup, doctor health, and provider setup/onboarding input.User Impact
Users who accidentally persisted an onboarding command in
zai:defaultcan recover without manually deleting all auth state: current env/config Z.AI credentials are allowed to take over, andopenclaw doctornow tells them exactly which profile is malformed and what to paste instead. Future setup/onboarding attempts reject command text at input time.Real behavior proof
Exact steps or command run after this patch: a redacted local OpenClaw doctor/auth proof used an isolated temporary agent auth store, saved a fake malformed
zai:defaultAPI-key profile through OpenClaw's auth-profile store helper, loaded the real doctor/auth modules, built the health summary, and rannoteAuthProfileHealthwith keychain prompts disabled.Evidence after fix (redacted local OpenClaw doctor/auth path): Validation
real-doctor-auth-proof(pass, exit_code=0):Observed result after fix: the malformed static Z.AI profile is loaded from the auth store, classified as
missing [malformed_api_key], and surfaced by the doctor auth output with the direct remediation hint instead of being treated as usable auth.What was not tested: no real Z.AI credential was used and no live provider request was sent; the proof intentionally uses a fake command-shaped value and isolated temp auth store to avoid exposing credentials or touching user auth state.
Tests and validation
Target test file:
src/agents/auth-profiles/credential-state.test.ts,src/plugins/provider-auth-input.test.ts,src/commands/onboard-non-interactive/api-keys.test.ts,src/agents/model-auth.profiles.test.ts,src/agents/auth-health.test.ts, andsrc/commands/doctor-auth.profile-health.test.ts.Scenario locked in: documented
openclaw onboard --auth-choice ...andopenclaw onboard --non-interactive ... --auth-choice=... --zai-api-key ...command variants are rejected as malformed API keys; malformed stored Z.AI profiles are skipped in favor of current env auth; doctor printsmissing [malformed_api_key]; CLI option and non-interactive flag inputs reject command-shaped values before storing or returning them.Why this is the smallest reliable guardrail: the tests pin both recovery and prevention boundaries without adding provider-specific branches beyond the shared malformed-command classifier.
CLI API-key option and non-interactive flag regression tests:
node scripts/run-vitest.mjs src/plugins/provider-auth-input.test.ts src/commands/onboard-non-interactive/api-keys.test.ts --reporter=verboseFocused auth regression tests:
node scripts/run-vitest.mjs src/agents/auth-profiles/credential-state.test.ts src/plugins/provider-auth-input.test.ts src/commands/onboard-non-interactive/api-keys.test.ts src/agents/model-auth.profiles.test.ts src/agents/auth-health.test.ts src/commands/doctor-auth.profile-health.test.ts --reporter=verboseFormat check:
pnpm exec oxfmt --check src/agents/auth-profiles/credential-state.ts src/agents/auth-profiles/credential-state.test.ts src/plugins/provider-auth-input.ts src/plugins/provider-auth-input.test.ts src/commands/onboard-non-interactive/api-keys.ts src/commands/onboard-non-interactive/api-keys.test.ts src/agents/auth-health.ts src/agents/auth-health.test.ts src/agents/auth-profiles/oauth.ts src/agents/model-auth.profiles.test.ts src/commands/doctor-auth.ts src/commands/doctor-auth.profile-health.test.tsTest typecheck:
pnpm check:test-typesRisk checklist
--auth-choice; healthy stored profiles and env/config fallbacks are unchanged.Current review state
Which bot or reviewer comments were addressed?
openclaw onboardcommand variants with intervening flags and--auth-choice=are covered bycredential-state.test.tsandprovider-auth-input.test.ts.zai:defaultprofile loading asapi_key/zai, health classification asmissing [malformed_api_key], and doctor output with the remediation hint.--auth-choice; normal API-key, token, OAuth, keyRef, and SecretRef behavior is unchanged.--auth-choice.src/agents/auth-profiles/credential-state.tsnow covers documented onboard command variants, with regression tests for the missed forms.