You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Inline-editing a password / secret field on the detail page renders the mask as the value and writes it straight back #4221
Filed unassigned per Prime Directive #10, from the fall-through sweep for #4216. Split out from #4220 (the rest of that sweep) because the severity and the argument are different: this one writes a masked placeholder into a credential field.
What happens
packages/plugin-detail/src/InlineFieldInput.tsx has no branch for password or secret, so both reach the terminal raw text input at the end of the component. The detail hosts' editability gate (DetailSection / HeaderHighlight) excludes only readonly, computed and system fields, so neither type is held back: the pencil / double-click affordance appears on a credential field.
Both types are masked on read. The value the cell holds is therefore a placeholder, not the secret — so the inline editor seeds a plain text box with the mask, shows it in clear as if it were the current value, and saves it back verbatim if the user commits the row.
This decision is already written down, one package over
@object-ui/fields excludes both from in-place editing and gives exactly this reasoning — INLINE_EXCLUDED_FIELD_TYPES in FieldEditWidget.tsx:
Credentials — never inline-editable. Both are masked on read, so the cell has no real value to seed an editor with, and the grid's fallback is a PLAIN TEXT input: it would render the mask as if it were the value and write it straight back. secret additionally round-trips through an encrypted store (ADR-0100, data/field.zod.ts) — the cell holds an opaque ref, not the secret.
The grid honours that set. InlineFieldInput never consults it, so the detail page reproduces the exact failure the set exists to prevent — including, for secret, writing a mask over what should be an opaque reference into an encrypted store.
Why it is not "just" a corrupted field
Two distinct harms beyond the overwrite:
Disclosure shape — the mask is rendered in a type="text" input, so whatever the mask contains is displayed in clear and is selectable/copyable, in a control the user believes holds their credential.
Silent credential loss — committing the row replaces a working secret with the placeholder, and nothing in the flow says so. The failure surfaces later, wherever that credential is used.
Likely shape of a fix
Make both non-editable inline on the detail path, by the same rule the grid uses — have the hosts' editability gate consult isInlineExcludedFieldType() from @object-ui/fields rather than growing a second hand-maintained list. Pin it: a password and a secret field must render no inline-edit affordance and must not produce an editor. Re-authoring a credential belongs in the record form, which has the widget for it (PasswordField).
Related: #4220 (the remaining fall-through classes and the FieldEditWidget duplication behind all of them), #4219 (autonumber slipping the computed gate), #4216 (the object-valued composites).
CLAIM (objectui whole-repo seat PM, session session_017Qqyix2QcnpUC9XeYVDzx3) — graded queue+bug on filing (credential loss + disclosure shape) and dispatching a dev agent now.
Scope per the card's own fix shape: the detail hosts' editability gate consults isInlineExcludedFieldType() from @object-ui/fields — the grid's rule, no second hand-maintained list. Pin: password/secret render no inline affordance and produce no editor.
ACCEPT (objectui seat PM, session session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4228. Held at draft (fourth in the hold queue behind the train-finisher): its three CI reds are the pre-existing main fallout, proven twice over, with the dev's own tests green inside CI's shards.
The wiring is the card's shape exactly — one helper in the shared fieldEnrichment module delegating to isInlineExcludedFieldType() (the grid's contract, alias-aware, narrow-only union mirroring the #3355 pattern), one conjunct added per host, zero new lists. The premise refinement matters and is recorded: the editor seeds from the PAYLOAD value, not the mask renderer — for secret the clear-text box was showing the ADR-0100 encrypted-store reference itself. The blast-radius table is measured on-branch with the gates reverted, and its hard case was handled with exactly the right instrument: the six binary/media types are EXEMPTED because InlineFieldInput genuinely routes them, with each exemption pinned twice (real member of the shared set AND really rendering a non-terminal editor) so an exemption that outlives its routing fails the suite — the anti-drift invariant this whole family needed.
Delegated ruling on the open question (veto window open): A, as shipped — markdown/html/richtext stay excluded. A one-line type="text" box over a multi-paragraph document is a truncation path, not a working editor; exempting them would admit the only entry NOT backed by a real widget, breaking the invariant that makes the exemption trustworthy. If there is pull for real inline editors for those types, that is #4220's routing-design half.
Cross-card effects, recorded: the CONTAINER half of #4220 is closed here (pinned no-longer-editable) — #4220 re-scopes to arrays + the type-lossy scalars inside the set's "editable" verdict + the delegate-vs-route ruling. #4219's user-facing defect (inline-editable autonumber) appears CLOSED by the alias resolution — the seat will verify and close it rather than dispatch. The serialization judgment (30 min of polling, then measured file-disjointness, then a mid-run rebase onto the landed #4222 with its types pinned as controls) is the discipline applied with sense rather than ritually. CI colour context: read against #4231.
Activity
yinlianghui commentedon Aug 11, 2026
CLAIM (objectui whole-repo seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3) — graded queue+bug on filing (credential loss + disclosure shape) and dispatching a dev agent now.claude/issue-4221-inline-credential-gate, worktreeobjectui-issue-4221(S/M container)isInlineExcludedFieldType()from@object-ui/fields— the grid's rule, no second hand-maintained list. Pin:password/secretrender no inline affordance and produce no editor.INLINE_EXCLUDED_FIELD_TYPESlikely also carries the container types Inline edit still destroys array-valued and container field values on the detail page (the rest of the #4216 fall-through sweep) #4220 records — if consulting the set closes that half of Inline edit still destroys array-valued and container field values on the detail page (the rest of the #4216 fall-through sweep) #4220 too, say so with the per-type list, and the seat re-scopes Inline edit still destroys array-valued and container field values on the detail page (the rest of the #4216 fall-through sweep) #4220 to its remaining routing-design half (arrays + type-lossy scalars + the delegate-vs-route ruling).[Object]#4222 (merged-pending) touchesInlineFieldInput.tsx— first edit waits until it is onorigin/main(git-layer polling).Generated by Claude Code
yinlianghui commentedon Aug 11, 2026
ACCEPT (objectui seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4228. Held at draft (fourth in the hold queue behind the train-finisher): its three CI reds are the pre-existing main fallout, proven twice over, with the dev's own tests green inside CI's shards.The wiring is the card's shape exactly — one helper in the shared
fieldEnrichmentmodule delegating toisInlineExcludedFieldType()(the grid's contract, alias-aware, narrow-only union mirroring the #3355 pattern), one conjunct added per host, zero new lists. The premise refinement matters and is recorded: the editor seeds from the PAYLOAD value, not the mask renderer — forsecretthe clear-text box was showing the ADR-0100 encrypted-store reference itself. The blast-radius table is measured on-branch with the gates reverted, and its hard case was handled with exactly the right instrument: the six binary/media types are EXEMPTED becauseInlineFieldInputgenuinely routes them, with each exemption pinned twice (real member of the shared set AND really rendering a non-terminal editor) so an exemption that outlives its routing fails the suite — the anti-drift invariant this whole family needed.Delegated ruling on the open question (veto window open): A, as shipped — markdown/html/richtext stay excluded. A one-line
type="text"box over a multi-paragraph document is a truncation path, not a working editor; exempting them would admit the only entry NOT backed by a real widget, breaking the invariant that makes the exemption trustworthy. If there is pull for real inline editors for those types, that is #4220's routing-design half.Cross-card effects, recorded: the CONTAINER half of #4220 is closed here (pinned no-longer-editable) — #4220 re-scopes to arrays + the type-lossy scalars inside the set's "editable" verdict + the delegate-vs-route ruling. #4219's user-facing defect (inline-editable
autonumber) appears CLOSED by the alias resolution — the seat will verify and close it rather than dispatch. The serialization judgment (30 min of polling, then measured file-disjointness, then a mid-run rebase onto the landed #4222 with its types pinned as controls) is the discipline applied with sense rather than ritually. CI colour context: read against #4231.Generated by Claude Code
fix(detail): a credential field is never inline-editable on the recor…