feat(dashboard): add the settings panel for flagged-file delivery consent - #9010
feat(dashboard): add the settings panel for flagged-file delivery consent#9010chenmingwei23 wants to merge 1 commit into
Conversation
Design Review (Fable 5) — 🟡 CONCERNSDesign-level review of Design-Verdict: CONCERNS Sound step-up design correctly mirroring Watch
Suggestions
[DESIGN-REVIEWED] 71e68b2 |
First Principles Review (Fable 5) — 🟡 CONCERNSPremise-level review of First-Principles-Verdict: CONCERNS The step-up earns its place, but two approve-time refusals that can permanently disable the feature are undeclared, and the new floor rule's stated justification is contradicted by the diff's own sandbox mask. What this change shipsIntent: let an owner get their own scanner-flagged file (e.g. a VPN key) delivered, with consent that an agent driving the owner's browser cannot grant. ADDITION. (Capped at 10 items; the capture script and committed PNGs follow the existing
Watch
Subtractions
[FIRST-PRINCIPLES-REVIEWED] 71e68b2 |
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
Opus 4.8 Review — ✅ no blocking findingsReviewed Review detailsNow I have what I need. The global Two advisory UI-state bugs in the file-delivery card; nothing blocks the merge. FINDING — website/src/pages/settings/SecurityPanel.tsx:2712 — after a host FINDING — website/src/pages/settings/SecurityPanel.tsx:2905 — when the arm-status GET starts failing after a successful arm, [OPUS-REVIEWED] 71e68b2 Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
UX Review (Fable 5) — 🟡 CONCERNSUX-level review of All evidence reviewed: the blind read reconciles cleanly against the diff (every state the reader saw was read correctly, including the arm step-up and the same-thing continuity across off → waiting → allowed), screenshots match the code, and the remaining issues are consistency drift and missing evidence rather than comprehension failures. Final review: UX-Verdict: CONCERNS Comprehension held across every captured state; what remains is "Withdraw" clashing with this panel's established "Revoke", plus unshown expiry/copy states. Watch
Evidence gaps
Suggestions
[UX-REVIEWED] 71e68b2 |
fbe34aa to
8993f6d
Compare
8993f6d to
fb428f0
Compare
fb428f0 to
e65fbf0
Compare
e65fbf0 to
fa5ec33
Compare
fa5ec33 to
006fd80
Compare
1785ba1 to
0498cdd
Compare
0498cdd to
dc954dd
Compare
dc954dd to
01851a1
Compare
…7770) Adds a Security-panel path for the owner to allow delivery of a file the credential scanner flags, recorded as a durable grant every delivery gate re-reads. Recording a grant takes a human-only step-up: the owner ARMS on the SPA and completes it with 'kirocrew file-delivery approve' on the host, which consumes a single-use nonce and records the grant via a loopback-only endpoint. Because the nonce lives on the sandbox-VISIBLE trust/ leaf, the step-up is made agent-proof by a new 'self-protection-file-delivery' denied-command floor rule (mirroring 'self-protection-update'): a prompt-injected agent cannot run the approve verb, so it cannot self-grant delivery of the owner's secrets. Consent copy is plain-language and names the use case; the armed step-up shows the host command and a human-readable expiry.
01851a1 to
71e68b2
Compare
|
Parked as a draft pending internal discussion. Not abandoned, and not waiting on CI -- the board What is settled on this head. The crash-safety ordering defect is fixed and verified: the What is not settled, and why it needs a decision rather than another patch. The posture fences The distinction worth preserving: this is a narrowed window described as narrowed, not a closed #9160 is the place for the mechanism discussion, since the same arm-in-the-dashboard, |
|
Tried to rebase this onto main
Pick a tier: ungated floor (drop the row, golden entry and opt-out), or keep the row. The A maintainer push would also make the maintainer last pusher, so a second approver would be needed. Reply if this reads wrong. |
Problem / Motivation
Kiro Crew refuses to deliver a file whose contents the credential scanner flags,
with no consented way through -- so a VPN device key the owner legitimately needs
delivered is blocked, and the feature reads as broken rather than protective
(issue #7770). This PR adds an owner-consented delivery path, recorded as a
durable grant every delivery gate re-reads.
The hard part is that this grant authorizes a secret-bearing file past four
independent content gates, so the consent point IS a security boundary -- and the
issue's own acceptance is that consent must be "a human dashboard action", not
something a background agent can grant on the owner's behalf.
Why it matters
An owner dashboard session proves identity, not human presence: anyone running
computer use points an agent at an owner-authenticated browser, so an
owner-session check alone lets a prompt-injected, auto-approved click record a
grant and make every later flagged file deliverable -- the exact "agent can
self-approve" hole #7770 exists to close. And a consent prompt the owner cannot
understand is not informed consent. The security boundary and the copy are the
two things this feature is actually about.
What changed (motivation -> approach -> change)
Security -- a human-only step-up, mirroring the established
update_stepuppattern (RFC OQ7) the repo already uses for "a dashboard session is not enough
authority for a security-critical write":
request and writes a single-use nonce;
kirocrew file-delivery approveon thehost consumes it and records the grant via a new loopback-only endpoint.
file-delivery-consent-pending/,registered in both
security._CREW_SECRET_LEAVES(file gate) ANDsandbox._CREW_HIDDEN_LEAVES, so it is bind-masked out of the agent sandbox inevery mode. It is deliberately NOT under
trust/, which is sandbox-VISIBLE forSEL appends and would let a prompt-injected agent forge a nonce there with a
runtime-constructed shell path. Because that directory is created lazily at arm
time, it is also added to
sandbox._CREW_PRECREATE_HIDDEN_DIR_LEAVESso themask binds over it before any sandbox spawns on a fresh install
(
aws-control-stagingis the precedent)._STRICT_INTERNAL_API_PATHS(notMIXED), exactly like its sibling
/api/update/approve: loopback +X-Internal-Secret only, no cookie fall-through, so a dashboard/agent bearer
cannot even reach the handler. The handler also re-asserts host-locality.
self-protection-file-deliverydenied-command FLOOR rule blocks the agentfrom running the approve verb through its own shell at all, mirroring
self-protection-update. Defence in depth alongside the mask.desktop input synthesis would let a prompt-injected agent type the approve
command into a host terminal and complete the owner's armed step-up itself, so
that one tier is excluded rather than trusted (reads the fail-safe-to-disabled
keystone
computer_use.json).pending-nonce mask: with
agent.sandboxoff (or no backend + unsandboxed execopted in) the nonce is unmasked and an unsandboxed agent could read or forge it
directly, so the presence proof is void. Uses the same security-reviewed
credential_mask_appliespredicate the ACP tool gate uses, which fails closed.fail-safe direction.
it validates the nonce, records the grant, and only then clears the single-use
nonce. A grant-write failure therefore leaves the nonce valid and the owner can
retry, instead of a 500 that also destroyed the armed request; single-use still
holds because the nonce is cleared on the success path before the response.
UX -- plain language and a stated purpose at the point of consent:
file_delivery_descnow names the use case ("Use this when a file of your own-- like a VPN key -- was blocked on its way to you"), the piece a blind reader
said it needed before it would allow anything.
one-line helper naming the outbox folder and the Files view, and stating it
never goes to Slack or a chat channel; never-grantable legs are described in
words, not the raw ids.
allowed"; the armed expiry renders as a human duration ("about 10 minutes"),
not raw seconds; em dashes match the catalogue.
ErrorNoticeinstead of silentlydropping the command panel. While a request is armed the row shows a "Waiting
for approval" badge and a disabled "Waiting on this machine" CTA (so a re-click
is not an invisible re-arm); the host command has a Copy button; an expired
armed request leaves a line rather than a silent unmount.
kirocrew file-deliveryCLI verb requires itsapproveaction (nonargs="?"): a bare invocation errors instead of silently approving.docs/feature-map/README.mdcorrected to state the real boundary (arm isowner-gated; recording is the host-only nonce step-up; the masked nonce leaf
plus the floor rule are the agent fences) -- the prior line called the
endpoints owner-gated, which this change made false.
i18n path, en-XA regenerated by
gen-pseudolocale.mjs), passing theper-language style gates (Italian accents, zh-CN particle stacking, Hindi
informal register).
Default preserved: delivery is still refused until the owner allows it, so nothing
changes until a human opts in on the host.
Tests
test/test_file_delivery_consent.py,test/test_denied_commands_security.py,test/test_sandbox_governance_mask.py,test/test_sandbox_absent_ceiling_seal.pyand
test/test_mcp_call_site_auth_coverage.py(run-n0): arm->approveround-trip;
TestGrantRequiresAHostStepUppins arm-records-nothing,remote-approve-refused, wrong-nonce-refused, single-use, the nonce leaf is
masked, the precreate materialises the leaf before spawn, the approve endpoint
is STRICT-not-MIXED, and approve is refused while computer use is enabled but
allowed when disabled. Mutation-verified: the floor rule, the mask leaf, the
precreate entry, the STRICT entry and the computer-use fence each redden a test
when removed.
SecurityPanel.fileDelivery.test.tsx: clicking Allow ARMS (recordsnothing) and shows the host command with the disabled waiting CTA, and a Copy
button; a failed arm-status read is surfaced. tsc clean.
renderScan, and the per-locale style specs; en-XA is generator-produced.
Manual verification
Rendered the panel through the capture harness against the built SPA and read the
frames: the resting state (use-case sentence + plain destination), the armed
step-up showing
kirocrew file-delivery approvewith "expires in about 10minutes", the write-failure notice, and the arm-status-failure notice. The
capture harness asserts each failure notice actually rendered before shooting, so
it cannot emit a plausible frame of the wrong state.
Screenshots / video
Resting state -- plain destination, the use-case sentence, "Allow delivery":
Armed step-up -- the click did NOT record a grant; the host command finishes it,
with a human-readable expiry:
Write-failure state:
All capture states are committed under
temp-screenshots/file-delivery-consent/;see the Files changed tab as a fallback.
Related Issues
Closes #7770
Out of scope (tracked separately)
The UX review (Fable 5) raised one blocker that this PR deliberately does not
fix: the consent card does not name the specific file that was refused, so the
owner has no concrete event to anchor the decision to. It is a valid concern, but
its only faithful implementation is a new surface -- the refused-file event is
written to no owner-readable store today (
audit_decisionrecords onlygranted/revoked/delivered, never the refusal, and there is no SEL readpath in the app surface), so surfacing it needs a new refusal-capture store, a new
read endpoint, and card rendering. That is filed as #9091 and is not folded here,
to keep this PR's security-critical surface reviewable. The reviewer's suggested
source ("from the SEL entry
audit_decisionalready writes") does not exist forrefusals -- the concern is real, the proposed remedy is not, and #9091 carries the
correct one. This PR does fold the review's smaller, frontend-only items: an
armed-state badge and a disabled "Waiting on this machine" CTA while armed, a Copy
button on the host command, an expired-request line instead of a silent unmount,
the long-duration expiry form, and the missing arm-status-failed screenshot.
Pattern harvest
security-critical write reachable by an agent-driven owner browser needs a
host-only step-up, and the step-up is only as strong as the fences around its
nonce: the nonce must live on a sandbox-MASKED leaf (a sandbox-visible one can
be forged with a runtime-constructed shell path), the leaf must be pre-created
so the mask binds before spawn, the approve endpoint must be STRICT-internal so
no cookie bearer reaches it, the CLI verb must be on the self-protection floor,
and the one tier that can synthesize host presence (computer use) must be
excluded.
update_stepupis agent-proof because these hold together; each wasa distinct review finding on this PR where one was missing.
old one, and comments are what no test covers -- grep the tree for the old
description, not just the line the reviewer named.
destination label and a stated purpose are where informed consent is won or
lost.