Repository navigation
🔒 Protect marked elicitation values during execution and replay - #1100
Conversation
PR #1100: 🔒 Protect marked elicitation values during execution and replay55 files, +3609 / -216 Scope🔴 PR has 3825 lines changed. Split into focused PRs. 🟡 3825 lines changed. PRs under 400 receive more thorough review. 🟡 55 files changed. Are all changes related? 🟡 Changes span 10 directories. StructuralOxlint structural signals:
SlopOxlint slop signals:
Static AnalysisOxlint: 301 diagnostics across 19 files (25 rules) no-shadow (103): packages/cli/tests/support/headless-repl.ts, packages/core/src/components/Elicit.ts, packages/core/src/secrets/inputs.ts (+5) CorrectnessNo extraneous code patterns detected. |
taras
left a comment
There was a problem hiding this comment.
Independent Fable review and affected closeout: PASS on 33005881b274c862583a41fb9326f66ca467af9b.
The complete feature was reviewed at 3fd110e3, covering all six accepted behavior clauses. The original reviewer then checked the eight-file correction at this head, carrying that coverage forward. No blocking finding remains.
- The host-tail cleanup blocker is fixed. Both original held-prefix/no-newline and trailing-newline probes finish cleanly; the real REPL regression covers both channels and normal, silent and bound command routing.
- Ordinary missing-final-member interpolation is restored, and the stale workflow-provider comment is corrected.
- Two observations remain nonblocking: document-time Context selection differs from stronger literal wording in the boundary packet while publication enforcement captures its owner; unmarked forwarded bytes normalize invalid UTF-8, with per-chunk cost unmeasured. Their retention grants no rule waiver or claim of literal packet compliance.
Architect and Planner also pass this exact head. Focused correction evidence passes (Core 15 groups/83 steps; host 6 groups/11 steps), alongside the retained frozen matrix and its candidate attribution. Required CI remains a separate merge gate.
taras
left a comment
There was a problem hiding this comment.
Independent Fable affected closeout: PASS at 624dba0124760cd5c2a2bb1718a16ad4435567b1 (parent 33005881). The completed full review and prior F1 closeout remain retained evidence; this is the seven-file CI repair closeout, covering B1–B6 with no blocking finding.
The repair preserves the existing TypeScript target, removes a validation initialization cycle without changing error identities, omits optional secret metadata on unmarked fields, and serializes errors before the existing selective disclosure projection. The serialization is in-memory and followed by the same redaction; protocol/codec identities and the R1/F1 paths remain intact. Existing D1, X1 and UI13 assertions are unchanged. Recorded focused Node typechecking, 14 separate-process Deno/Bun initialization runs, REPL assertions and protected-input controls pass. Original Architect and Planner also pass this exact head.
Two earlier nonblocking observations remain explicit: consumer-time Context selection differs from the stronger design-packet wording, with no waiver claimed; unmarked forwarded output normalizes invalid UTF-8 and its per-chunk cost is unmeasured. No full review or UX benchmark was repeated for this repair.
Required CI2416 is pending on this corrected commit. This comment records the independent review outcome; it is not a merge approval.
taras
left a comment
There was a problem hiding this comment.
Independent Fable affected closeout: PASS at aff1410b2c605c775796a58b5d3aae0cfea2b716 (parent 624dba01). This covers only the Node fixture repair, carrying the completed feature review and B1–B6 coverage.
The committed file is byte-identical to its parent after exactly four provider.ts → provider.mjs substitutions. The temporary providers contain plain ESM JavaScript; .mjs selects the same module mode already used by other CLI plugin fixtures. The captured first stderr shows Node refused the .ts plugin before document work because CommonJS loading reached the import-only remend dependency. Recorded affected-file checks pass under Node, Deno and Bun.
Every disclosure assertion, unmarked negative control, real child invocation and controlled npm command spelling is preserved. No production loader, dependency, exclusion or assertion changed. The affected Planner also passes this exact head. Prior architecture coverage stands because production is unchanged.
The earlier N1 Context-selection and N3 invalid-UTF8/unmeasured-cost observations remain nonblocking and unwaived. No full feature review, architecture review or UX benchmark repeated. New corrected-head CI remains required; this comment records review findings and is not merge approval.
73dd168 to
e1392f5
Compare
taras
left a comment
There was a problem hiding this comment.
Independent Fable mechanical-rebase closeout: PASS at e1392f5d2167bd9c9c76873f3f57feb5e9dc08dc.
Mechanical-rebase closeout at e1392f5 (six feature commits replayed onto main 25368ab), carrying prior B1–B6 coverage. Independently recomputed from immutable Git objects: range-diff marks all six patches equal; the cumulative feature patch ID (acdd48b7…) is identical before and after; the new tree 9b473dd7 equals a conflict-free merge-tree of old head aff1410 with exact main; main is an ancestor; all six rewritten commits verify with a good signature; checkout clean at HEAD. Only architecture.md and specs/repl-spec.md overlap with main's changes, and per-path patch IDs show both the feature hunks and main's hunks preserved exactly. Every reviewed protected-input source and test blob is byte-identical to the previously passed head. No new execution was needed; no new-head CI success is claimed.
-
Rebase equivalence verified independently:
git range-diff 32b53ab9..aff1410b 25368ab1..e1392f5dshows six=rows;git diff 32b53ab9 aff1410b | git patch-id --stableandgit diff 25368ab1 e1392f5d | git patch-id --stableboth yield acdd48b798f090d16eb7f37b4ea92a37ae43d3fc;git merge-tree --write-tree 25368ab1 aff1410breturns 9b473dd7f699d060a49648ae526d5b75f3aedaad with exit 0, equal toe1392f5d^{tree}; path intersection of feature and main deltas is exactly architecture.md and specs/repl-spec.md, whose feature-side and main-side patch IDs are preserved; inputs.ts, input-host.ts, policy.ts, input-schema.ts, elicit-journal.ts, execute.ts, foreground.ts and protected-input-cli.test.ts have identical blob IDs at aff1410 and e1392f5;git verify-commitsucceeds for all six new commits. -
Retained N1 (unchanged by the rebase): consumer-time
inputValues()Context selection remains a literal discrepancy with the boundary's captured-owner sentence; no waiver or compliance claimed. -
Retained N3 (unchanged by the rebase): route() decodes and re-encodes forwarded bytes for all foreground commands; invalid UTF-8 becomes replacement characters and the per-chunk cost is unmeasured.
Prior full feature review and affected closeouts remain retained. This is exact-head equivalence review; required CI and repository merge gates remain authoritative.
Why
A runtime
<Elicit>credential can enter journals, eval snapshots, command records and displayed output. Short one-time codes are not reliably recognizable by the heuristic scanner. Authors need an explicit field-level guarantee.What changes
Before: an elicited string remains ordinary data and can be retained or displayed.
After: a top-level string property marked
writeOnly: truebecomes a protected value. Normal built-in exec interpolation receives the original string; XMD records, output and Sidekick feedback receive safe views. Unsupported conversions fail actionably before their dependent command runs.Partial continuation obtains fresh missing secret fields while keeping public answers and completed effects. Marked workflow questions use foreground live input; durable answer delivery refuses them before storage. A host without a live responder reports that requirement immediately.
How it works
An execution-owned input service keeps live values separate from field receipts. Eval history restores occurrence references rather than plaintext. Canonical command ownership carries language and protected segments together; safe command descriptions preserve protocol identities. Host filters remain installed through joined producer cleanup.
Review guide
Start with
packages/core/src/secrets/inputs.ts,input-record.tsandcomponents/Elicit.ts. Follow recording/projection insecrets/policy.ts, then host installation and the marked workflow route. Review REPL/browser masking and Sidekick answer projection at their existing owners.Look carefully at the distinction between disclosure payloads and durable identities, partial replay without repeated effects, and output after root Close or Stop. The protocol-collision regression covers the correction found in architecture review.
What must stay true
How to verify it
The frozen M1–M11 matrix covers Core, actual CLI publication modes, REPL cleanup/History, workflow delivery, ACP and web forms. Candidate-to-commit receipts preserve which inputs each command tested. Later witness assertions and the protocol-identity correction have focused passing receipts.
Documentation validation and the web bundle build pass. Architecture passed the production head
624dba01; the subsequent fixture-only correction passed its affected Planner and independent Fable closeout ataff1410b. The signed six-commit series is rebased onto main25368ab1ate1392f5d. Independent Fable rebase closeout confirms all six patches, every reviewed protected-input source/test blob, and both overlapping documentation changes are preserved. The completed feature review remains retained. Required CI remains a delivery gate; runner-based corpus weights use the existing measurement workflow.CI run 2414 exposed four integration causes. A seven-file correction preserves the configured TypeScript target, removes a validation import cycle without moving error classes, omits secret metadata on ordinary fields, and serializes errors before selective disclosure projection. Existing D1, X1 and UI13 assertions stay unchanged. Focused Node typechecking and affected Deno, Node and Bun checks pass; complete first failed logs and candidate-to-commit receipts are retained. CI2416 then passed every substantive job except two actual-CLI tests under Node. Their generated
.tsproviders were loaded as CommonJS before document admission; naming the plain-JavaScript ESM fixtures.mjsfixes the import-only dependency failure without production or assertion changes. The exact test file passes under Node, Deno and Bun. The correctedaff1410bhead passed CI2417. The rebasede1392f5dhead has separate required verification in CI2423; no branch-protection gate is waived.Scope
This delivery covers top-level Elicit string properties and built-in exec's supported forms. It includes REPL/browser presentation, Sidekick feedback, workflow routing and the bootstrap OTP. Unsupported marking shapes and conversions refuse. Ordinary unmarked input, native JSON behavior and the separate TempDir continuation restriction keep their existing contracts.
New abstractions
The execution-owned protected-input service serves elicitation, eval replay, command execution and host output cleanup. Its private field-reference codec preserves replay without storing plaintext. Neither exposes a reveal API or introduces a global secret registry, dependency or record-version layer.
Risks and limitations
The confidentiality boundary covers accidental disclosure through supported XMD behavior. Explicitly executed documents and installed extensions remain trusted. The external process still receives the secret it needs.
Two nonblocking review observations remain recorded: some document-time owner selection uses Context despite stronger literal wording in the design packet, while publication enforcement captures the owner; unmarked forwarded output normalizes invalid UTF-8 and its small per-chunk cost is unmeasured. These observations carry no rule waiver or claim of literal packet compliance.
Scope confirmation
Closes #462.