🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

fix(site): CredentialField: mask api key after submit - #25848

Merged
johnstcn merged 5 commits into
mainfrom
cj/ai-settings-api-key-masking
Jun 2, 2026
Merged

fix(site): CredentialField: mask api key after submit#25848
johnstcn merged 5 commits into
mainfrom
cj/ai-settings-api-key-masking

Conversation

@johnstcn

@johnstcn johnstcn commented May 29, 2026

Copy link
Copy Markdown
Member

Fixes CODAGT-525

  • Re-masks the field after submit
  • Sets font to monospaced for legibility
  • Extracts createDeferred to testHelpers

@johnstcn

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Chat: Review posted | View chat
Requested: 2026-05-29 18:55 UTC by @johnstcn
Spend: $49.61 / $100.00

Review history
  • R1 (2026-05-29): 14 reviewers, 1 Nit, 2 Note, 1 P2, 3 P3, COMMENT. Review
  • R2 (2026-05-29): 8 reviewers, 2 Nit, 2 Note, 2 P2, 6 P3, COMMENT. Review
  • R3 (2026-05-29): 4 reviewers, 2 Nit, 2 Note, 2 P2, 6 P3, APPROVE. Review

deep-review v0.6.0 | Round 3 | d0a51da..253b738

Last posted: Round 3, 12 findings (2 P2, 6 P3, 2 Nit, 2 Note), APPROVE. Review

Finding inventory

Finding Inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P3 Author fixed (e8f48f9) ProviderForm.stories.tsx:147 CredentialFocusClear story submits form but never exercises re-masking useEffect (isLoading never transitions true->false) R1 Netero, Bisky Yes
CRF-2 P3 Author fixed (e8f48f9) ProviderForm.tsx:396 Bedrock accessKey missing autoComplete="new-password", now consequential with type="password" R1 Hisoka P3, Mafuuu P3, Pariston P3, Nami P3, Chopper Nit, Razor P3 Yes
CRF-3 P2 Author fixed (e8f48f9) CredentialField.tsx:65 type="password" hides distinguishing masked sentinel from API, defeating key identification R1 Mafuuu P2, Kite P3, Nami Note, Hisoka Note Yes
CRF-4 P3 Author fixed (e8f48f9) ProviderForm.stories.tsx:156 Submit callback mock never verified for payload integrity R1 Chopper Yes
CRF-5 Nit Author fixed (e8f48f9) ProviderForm.stories.tsx:71 Story comments restate what assertions already say (4 instances at lines 71, 139, 146, 152) R1 Gon Yes
CRF-6 Nit Dropped by orchestrator (not postable as inline; included in review body) PR description PR description restates diff instead of naming the problem R1 Leorio No
CRF-7 Note Author fixed (e8f48f9) ProviderForm.tsx:290 Re-masking uses mount-time sentinel, not server's current mask (invisible with type=password) R1 Hisoka Yes
CRF-8 Note Author fixed (e8f48f9) ProviderForm.tsx:288 Re-masking hardcodes three field names; a fourth field needs manual addition R1 Hisoka, Kite Yes
CRF-9 P3 Author fixed (253b738) ProviderForm.stories.tsx:24 createDeferred utility duplicated across three files; existing generic copies in testHelpers R2 Netero Yes
CRF-10 P2 Author fixed (253b738) ProviderForm.tsx:299 Toggle-mutation completes isLoading cycle, overwriting in-progress credential edits with masked values R2 Hisoka Yes
CRF-11 P3 Author fixed (253b738) ProviderForm.tsx:301 No test for submit-error path; useEffect guard is only thing preventing credential destruction on failure R2 Bisky Yes
CRF-12 P3 Author fixed (253b738) ProviderForm.tsx:285 handleCredentialBlur has no comment, but its paired handleCredentialFocus does R2 Leorio Yes
CRF-13 Nit Dropped by orchestrator (moved comment, pre-existing content, scope creep) ProviderForm.tsx:241 Comment restates ternary R2 Gon No
CRF-14 Nit Dropped by orchestrator (moved comment, pre-existing content, scope creep) ProviderForm.tsx:249 "Same pattern" cross-reference adds no info R2 Gon No
CRF-15 Nit Author fixed (253b738) ProviderForm.stories.tsx:123 PR description and commit subject claim "password input type" but code uses type="text" R2 Leorio, Pariston Yes

Contested and acknowledged

(none)

Round log

Round 1

Panel. 1 P2, 3 P3, 1 Nit, 2 Note. 1 Nit dropped (PR description, not postable). Reviewed against d0a51da..2e57865.

Round 2

Churn 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 3

Churn 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-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread site/src/pages/AISettingsPage/ProvidersPage/components/CredentialField.tsx Outdated
Comment thread site/src/pages/AISettingsPage/ProvidersPage/components/ProviderForm.stories.tsx Outdated
Comment thread site/src/pages/AISettingsPage/ProvidersPage/components/ProviderForm.stories.tsx Outdated
Comment thread site/src/pages/AISettingsPage/ProvidersPage/components/ProviderForm.tsx Outdated
Comment thread site/src/pages/AISettingsPage/ProvidersPage/components/ProviderForm.tsx Outdated
@johnstcn
johnstcn force-pushed the cj/ai-settings-api-key-masking branch from 2e57865 to e8f48f9 Compare May 29, 2026 15:58
@johnstcn johnstcn changed the title fix(site/src/pages/AISettingsPage/ProvidersPage): use password input type and mask after submit fix(site): use password input type and mask after submit May 29, 2026
@johnstcn johnstcn changed the title fix(site): use password input type and mask after submit fix(site): CredentialField: mask api key after submit May 29, 2026
@johnstcn

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread site/src/pages/AISettingsPage/ProvidersPage/components/ProviderForm.tsx Outdated
Comment thread site/src/pages/AISettingsPage/ProvidersPage/components/ProviderForm.stories.tsx Outdated
@johnstcn

Copy link
Copy Markdown
Member Author

/coder-agents-review

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@johnstcn
johnstcn marked this pull request as ready for review May 29, 2026 21:56
Copilot AI review requested due to automatic review settings May 29, 2026 21:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 createDeferred test 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.

@johnstcn
johnstcn merged commit 7195be8 into main Jun 2, 2026
29 checks passed
@johnstcn
johnstcn deleted the cj/ai-settings-api-key-masking branch June 2, 2026 10:55
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants