Skip to content

🔒 Protect marked elicitation values during execution and replay - #1100

Draft
taras wants to merge 5 commits into
mainfrom
codex/secret-elicitation-462
Draft

taras wants to merge 5 commits into
mainfrom
codex/secret-elicitation-462

Conversation

@taras

@taras taras commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

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: true becomes 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

marked field -> validation -> execution-owned protected value -> built-in exec
                                     |
                                     +-> safe records and output

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.ts and components/Elicit.ts. Follow recording/projection in secrets/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

  • Runtime-only secrets stay out of retained/displayed XMD data; paired unmarked and mark-removal controls distinguish explicit protection.
  • Completed effects do not repeat when fresh input is needed; unfinished-stream and equal-valued-field witnesses check occurrence identity.
  • Explicit marking remains protected with scanner opt-out; unrelated scanner behavior stays intact.
  • Missing live input refuses immediately; capable ACP over pipes remains interactive.

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.

deno task test packages/core/tests/protected-input.test.ts packages/core/tests/protected-input-replay.test.ts
deno task test packages/cli/tests/protected-input-cli.test.ts packages/cli/tests/protected-input-forms.test.ts

Documentation validation and the web bundle build pass. Architect and Planner pass 624dba01. The independent Fable review is retained, and its affected closeout passes this head. 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. The corrected head requires a new CI run.

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

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • Generated or mechanical changes are clearly identified.
  • The description matches the final diff and test results.

Closes #462.

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

PR #1100: 🔒 Protect marked elicitation values during execution and replay

55 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.

Structural

Oxlint structural signals:

  • no-unused-vars ×36: packages/cli/tests/support/headless-repl.ts, packages/core/src/execute.ts, packages/cli/src/repl/session.ts (+3)
  • no-unnecessary-type-assertion ×11: packages/cli/src/repl/elicitation.ts, packages/core/src/modifiers.ts, packages/core/src/execute.ts (+2)
  • no-empty-function ×7: packages/core/src/secrets/input-schema.ts, packages/cli/src/repl/elicitation.ts, packages/core/src/secrets/inputs.ts (+3)
  • no-unnecessary-type-arguments ×4: packages/cli/src/repl/session.ts, packages/cli/src/repl/elicitation.ts, packages/cli/src/repl/sidekick/owner.ts
  • no-unnecessary-boolean-literal-compare ×1: packages/cli/src/repl/application.ts

Slop

Oxlint slop signals:

  • no-console ×3: packages/cli/src/cli.ts
  • no-inferrable-types ×2: packages/core/src/expand.ts

Static Analysis

Oxlint: 301 diagnostics across 19 files (25 rules)
Density: 0.083 violations/added-line

no-shadow (103): packages/core/src/components/Elicit.ts, packages/cli/tests/support/headless-repl.ts, packages/core/src/secrets/inputs.ts (+5)
no-unused-vars (36): packages/cli/tests/support/headless-repl.ts, packages/core/src/execute.ts, packages/cli/src/repl/session.ts (+3)
no-useless-default-assignment (36): packages/cli/src/repl/application.ts, packages/core/src/expand.ts
unbound-method (20): packages/cli/src/repl/session.ts, packages/cli/tests/support/headless-repl.ts, packages/cli/src/cli.ts (+2)
no-unsafe-type-assertion (17): packages/core/src/modifiers.ts, packages/cli/src/cli.ts, packages/core/src/execute.ts (+3)
consistent-function-scoping (11): packages/core/src/secrets/inputs.ts, packages/core/src/execute.ts, packages/core/src/modifiers.ts (+2)
no-unnecessary-type-assertion (11): packages/cli/src/repl/elicitation.ts, packages/core/src/modifiers.ts, packages/core/src/execute.ts (+2)
consistent-return (10): packages/core/src/secrets/input-host.ts, packages/core/src/execute.ts, packages/cli/src/cli.ts (+1)
no-underscore-dangle (8): packages/core/src/eval-handler.ts, packages/core/src/expand.ts, packages/web/client/main.tsx
no-floating-promises (8): packages/cli/src/repl/session.ts, packages/core/tests/support/protected-input.ts, packages/web/client/main.tsx (+1)
no-empty-function (7): packages/core/src/secrets/input-schema.ts, packages/cli/src/repl/elicitation.ts, packages/core/src/secrets/inputs.ts (+3)
no-base-to-string (7): packages/core/src/eval-handler.ts, packages/core/src/expand.ts
no-duplicate-type-constituents (5): packages/core/src/execute.ts, packages/cli/src/repl/application.ts
no-array-sort (4): packages/core/src/secrets/inputs.ts, packages/core/src/execute.ts, packages/core/src/expand.ts (+1)
no-unnecessary-type-arguments (4): packages/cli/src/repl/session.ts, packages/cli/src/repl/elicitation.ts, packages/cli/src/repl/sidekick/owner.ts
no-console (3): packages/cli/src/cli.ts
no-unmodified-loop-condition (2): packages/cli/tests/support/headless-repl.ts, packages/cli/src/cli.ts
no-inferrable-types (2): packages/core/src/expand.ts
no-unused-private-class-members (1): packages/core/src/secrets/policy.ts
no-useless-fallback-in-spread (1): packages/core/src/expand.ts
no-useless-spread (1): packages/cli/src/cli.ts
no-unnecessary-type-conversion (1): packages/core/src/eval-handler.ts
restrict-template-expressions (1): packages/core/src/expand.ts
no-implied-eval (1): packages/core/src/expand.ts
no-unnecessary-boolean-literal-compare (1): packages/cli/src/repl/application.ts

Correctness

No extraneous code patterns detected.

@taras taras left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

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 taras left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

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.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keep secrets from <Elicit> out of journals and verbose output

1 participant