fix(site): CredentialField: mask api key after submit - #25848
Conversation
|
/coder-agents-review |
|
Chat: Review posted | View chat Review historydeep-review v0.6.0 | Round 3 | Last posted: Round 3, 12 findings (2 P2, 6 P3, 2 Nit, 2 Note), APPROVE. Review Finding inventoryFinding InventoryFindings
Contested and acknowledged(none) Round logRound 1Panel. 1 P2, 3 P3, 1 Nit, 2 Note. 1 Nit dropped (PR description, not postable). Reviewed against d0a51da..2e57865. Round 2Churn guard: PROCEED. All 7 open findings addressed in e8f48f9. Panel: 1 P2, 3 P3 new. 2 Nit dropped (scope creep on moved/pre-existing comments). 1 Nit in body (PR description/commit). Reviewed against d0a51da..e8f48f9. Round 3Churn guard: PROCEED. All 5 R2 open findings addressed in 253b738. CRF-15 classified as contested by churn guard (author: "This will get squashed"), but PR description was actually updated (inaccurate bullet removed), so classified as addressed. Netero: no findings. Panel (Bisky, Hisoka, Mafuuu, Meruem): no findings. All 15 findings across 3 rounds resolved. Reviewed against d0a51da..253b738. About deep-reviewCRF = Coder Review Finding (P0-P4, Nit, Note)
|
There was a problem hiding this comment.
Clean, focused PR. The password masking and re-masking logic are mechanically sound, and the test coverage for type="password" assertions is genuine. Kurapika traced the full credential lifecycle and found no new attack surface. Mafu-san confirmed scope-to-problem proportionality.
One P2 (sentinel visibility defeated), three P3s (missing autoComplete, two test gaps), one Nit, two Notes.
The PR description lists implementation bullets without stating the problem. The PR style guide says bug fixes start with what was broken. Something like: "Credential inputs displayed API keys as plaintext, visible to shoulder-surfers and screen captures."
"The prop still functions mechanically, but its user-facing purpose is defeated. An admin editing a provider cannot tell which key is saved without leaving the form." (Mafuuu)
site/src/pages/AISettingsPage/ProvidersPage/components/ProviderForm.tsx:396-401
P3 [CRF-2] Bedrock "Access key" is now type="password" without autoComplete, triggering browser password-manager interactions.
Three CredentialField usages exist. apiKey (line 339) and accessKeySecret (line 407) both pass autoComplete="new-password". This accessKey does not. Before this PR the field was type="text", so the omission was dormant. Now with type="password", browsers will offer to autofill/save it.
Since CredentialField always renders type="password", it should own the autoComplete default rather than requiring each caller to remember. The structural fix is defaulting autoComplete to "new-password" in the CredentialField props:
// CredentialField.tsx, destructured props:
autoComplete = "new-password",This protects current and future callers while still allowing overrides.
(Hisoka P3, Mafuuu P3, Pariston P3, Nami P3, Razor P3, Chopper Nit)
🤖
🤖 This review was automatically generated with Coder Agents.
…type and mask after submit
2e57865 to
e8f48f9
Compare
|
/coder-agents-review |
There was a problem hiding this comment.
All seven R1 findings addressed cleanly. The approach pivot from type="password" to sentinel-based masking with blur-restore is well-reasoned, and the test infrastructure (SuccessfulSubmitProviderForm + deferred) is honest and deterministic. Mafuuu traced the full lifecycle end-to-end; Pariston verified against five framings of the problem. The setQueryData calls solve the stale-mask issue (CRF-7) at the right level.
One P2 (toggle-mutation credential overwrite), three P3s (missing error-path test, duplicated utility, missing paired comment).
The PR description and commit subject still claim "password input type" but the code ships type="text". After CRF-3's fix this is now factually wrong, not just restating the diff. Worth updating before merge so git log doesn't record a false statement about the security boundary.
"If someone removes or weakens the guard in a future refactor, the user types a new API key, submit fails, and the form silently replaces their key with ********. No test exercises the error path." (Bisky)
🤖 This review was automatically generated with Coder Agents.
|
/coder-agents-review |
There was a problem hiding this comment.
All 15 findings across three rounds are resolved. No new findings from Netero or the panel.
The credential lifecycle is now well-covered: focus clears the mask, blur restores it, submit sends the raw value, post-submit re-masks with the server's current sentinel, failed submits preserve the typed credential, and external loading cycles (toggle) don't interfere. The didSubmit ref cleanly discriminates form submissions from toggle mutations. The shared createDeferred utility consolidates three copies. Test density is 3.4:1.
Hisoka traced four adversarial scenarios (shared mutation, form instability in deps, blur-then-submit ordering, error path timing) and all held.
"The code fought well." (Hisoka)
🤖 This review was automatically generated with Coder Agents.
There was a problem hiding this comment.
Pull request overview
Fixes credential masking behavior in the AI provider form so saved credentials are restored to masked display after submit, while improving credential input legibility and reusing a shared deferred test helper.
Changes:
- Re-masks provider credential fields after successful submit and restores masks on empty blur.
- Updates AI provider cache after mutations so refreshed masked values are available promptly.
- Adds monospace styling for credential inputs and centralizes the
createDeferredtest helper.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
site/src/pages/AISettingsPage/ProvidersPage/components/ProviderForm.tsx |
Adds submit tracking, blur restoration, and post-submit credential re-masking. |
site/src/pages/AISettingsPage/ProvidersPage/components/CredentialField.tsx |
Adds optional blur callback and monospace credential input styling. |
site/src/pages/AISettingsPage/ProvidersPage/UpdateProviderPage/UpdateProviderPageView.tsx |
Seeds the provider query cache with mutation responses. |
site/src/api/queries/aiProviders.ts |
Exports the provider query key helper for cache updates. |
site/src/testHelpers/deferred.ts |
Adds shared deferred promise helper. |
site/src/pages/AISettingsPage/ProvidersPage/components/ProviderForm.stories.tsx |
Expands Storybook coverage for masking, blur, submit success/failure, and external loading. |
site/src/pages/AgentsPage/hooks/useChatDraftAttachments.test.ts |
Replaces local deferred helper with shared helper. |
site/src/pages/AgentsPage/AgentChatPage.test.ts |
Replaces local deferred helper with shared helper. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Fixes CODAGT-525
createDeferredtotestHelpers