Repository navigation
fix(dashboard): refuse unknown-slot approval-mode requests before any global mutation - #4472
Conversation
|
👋 Hi! This PR's description is missing some required sections from our PR template. Workflow runs won't be auto-approved until the description is updated. Missing sections:
Please update your PR description to include these sections, then push or re-save the description. The workflows will be approved on the next cycle. |
2 similar comments
|
👋 Hi! This PR's description is missing some required sections from our PR template. Workflow runs won't be auto-approved until the description is updated. Missing sections:
Please update your PR description to include these sections, then push or re-save the description. The workflows will be approved on the next cycle. |
|
👋 Hi! This PR's description is missing some required sections from our PR template. Workflow runs won't be auto-approved until the description is updated. Missing sections:
Please update your PR description to include these sections, then push or re-save the description. The workflows will be approved on the next cycle. |
c710fc2 to
54b4be6
Compare
|
👋 Hi! This PR's description is missing some required sections from our PR template. Workflow runs won't be auto-approved until the description is updated. Missing sections:
Please update your PR description to include these sections, then push or re-save the description. The workflows will be approved on the next cycle. |
1 similar comment
|
👋 Hi! This PR's description is missing some required sections from our PR template. Workflow runs won't be auto-approved until the description is updated. Missing sections:
Please update your PR description to include these sections, then push or re-save the description. The workflows will be approved on the next cycle. |
54b4be6 to
58ab1df
Compare
58ab1df to
65a520e
Compare
65a520e to
58f9657
Compare
|
CI note: all checks pass on this head (\58f9657) except Backend Tests (Windows) (1). The single failure is \ est_aidlc_store.py::TestProjectCRUD::test_list_projects\ (\�ssert '43f8024ec4fd' == 'e5a621a0834d') — a pre-existing timing-sensitive sort assertion (two \create_project\ calls land on the same \updated_at\ tick, so the tie-break order is unstable). The test file has not been touched since \79e7268\ and is unrelated to this PR's diff (which touches only \chat_handlers.py, \ est_chat_mode_security.py, \security.md, \error-code-baseline.json). Could this job be re-run? Thanks! |
58f9657 to
2a2af99
Compare
|
Kiro Crew [operator: chenmingwei23#de330d0c]: This PR has been inactive for 7+ days with a blocking check and merge conflicts. I have assessed the blockers and they appear resolvable -- I will push fixes directly to this branch as a co-author. Assessment: Branch is CONFLICTING (needs rebase onto main for a fresh merge ref). All Backend/Build/Design lanes are green; the only blocking check is First Principles, which asks for two bounded, mechanical subtractions on this PR own code, no design change: (1) revert the If you would prefer I do not touch this PR, add the |
|
🤖 Kiro Crew [operator: iamwhatever]: This PR has been inactive for 7+ days with failing CI. I've assessed the blockers and they appear resolvable — I'll push fixes directly to this branch as a co-author. Assessment: Two blockers, both mechanical. (1) The branch re-conflicted with If you'd prefer I don't touch this PR, add the |
7855c85 to
b7d3482
Compare
|
Rebased onto current Rebase / conflict resolution (
First Principles subtractions:
Verification (local): isort/flake8/mypy clean on touched files; PR body updated to match (the previous body's baseline-regeneration claim is removed). Co-authored-by trailer credits Kiro Crew; XiaoChen (c020627) remains the commit author. |
|
Status: the two red shards on head b7d3482 -- No fix is folded here (zero lines of this diff touch |
Drive-to-green diagnosis (automated)This PR was adopted by the drive-to-green reconciler. Diagnosis of head All failing checks are pre-existing
PR-side state is clean: single commit, 3 files, mergeable, 0 unresolved review threads, all 40+ other checks green. It is only 2 commits behind No code changes made. Escalating with |
… global mutation A slot-scoped POST /api/chat/mode request naming a slot that does not resolve is now a strict no-op refusal: 400 before safety_override() deactivation, no widening to every slot, no revocation of the live global grant. Non-string slot values are refused on the raw value before `or None` normalization can erase them into the all-slots request. deactivate() is offloaded with asyncio.to_thread matching the sibling activate(). 16 contract tests. Original fix authored by XiaoChen (c020627). Rebased onto current main: branch bodies adopt main's effective_session_key() shared- session propagation while keeping this PR's up-front validation, and main's now-redundant late unknown-slot checks are dropped. Review subtractions applied: error-code-baseline.json reverted to base (the diff adds no coded responses net, so no regeneration is needed) and the single-consumer _resolve_mode_slot() helper inlined at its call site. Closes kirodotdev#4454 Co-authored-by: Kiro Crew <[email protected]>
b7d3482 to
66d0dbc
Compare
|
Rebased onto current main (head b7d3482 -> 66d0dbc, zero code change -- clean rebase). The two inherited Backend Tests shard-4 reds (test_trust_reads |
|
Review-ready on head 66d0dbc.
Summary of the drive: rebased twice onto moving main (first to clear the original conflict, then to pick up the main-side fix for the inherited |
Problem / Motivation
POST /api/chat/mode(src/kiro_crew/dashboard/chat_handlers.py) carried three defects in the ordering between slot validation and global mutation:trust_readsrequest naming a slot that does not resolve silently fell through to the all-slots path, widening a slot-scoped request across every slot on the gateway. Itstrust/normalsiblings answer400 unknown slot.400sat aftersafety_override().deactivate(), so a refused request ({"mode": "normal", "slot": " "}) still revoked the process-global grant -- a rejected request mutated global state.deactivate()-- which emits a SEL event -- ran inline on the gateway loop, while the siblingactivate()is offloaded withasyncio.to_thread.Why it matters
The unknown-slot cases are exactly the malformed or stale requests an automation sends (e.g. a session created against a slot that was since deleted). Today those requests either widen a slot-scoped intent across every slot (defect 1 -- the
trust_readspath that other modes explicitly refuse) or withdraw a global grant the operator relies on (defect 2), while the blocked-deactivateinline run puts SEL I/O on the gateway event loop (defect 3). None of the three has a good outcome for the operator; each is a "rejected input should be a no-op" violation.What changed (motivation -> approach -> change)
trust_readsnever validated, andtrust/normalvalidated only after the global grant was already revoked. The fix is to make "slot does not resolve" a refusal that happens before any mutation, for every slot-scoped branch, and to stop re-indexingstate._slots[slot_key]after anawait(no check/use gap for a concurrent slot deletion).api_chat_mode, and an unresolvable key returns400before touching grant or slots. Branches mutate the captured slot reference instead of re-indexing the dict.yolois global and keeps ignoringslot(a stale key must not refuse it), preserving upstream behavior.body.get("slot") or Nonepreviously collapsed falsy non-strings ([],{},0,False) into the documented all-slots request -- so{"mode": "trust", "slot": []}trusted every slot (the same widening defect as api_chat_mode: trust_reads widens on an unknown slot, rejected requests still mutate, deactivate blocks the loop #4454 through a normalization back door). The raw value is now type-checked before that normalization: any present non-stringslotanswers400 unknown slot, whileyolostill ignoresslotentirely.src/kiro_crew/dashboard/chat_handlers.py-- hoist validation ahead of the conditionaldeactivate(); refuse present non-string slots on the raw value; offloaddeactivate()withawait asyncio.to_thread(...)matching the siblingactivate(). A slot-scopedtrust/trust_readsleaves the process-global grant alone (a per-slot request cannot be answered by withdrawing authority elsewhere); a grant declared in owner-only config is exempt from the narrowing, since selecting another approval mode is the one documented action that ends it.This branch is rebased onto the current
main. The branch bodies adopt main'seffective_session_key()shared-session propagation (the policy is per session, the flag is per slot, so a grant/revoke clears every slot sharing the session) while keeping this PR's up-front validation; main's now-redundant late unknown-slot checks inside thetrust/normalbranches are dropped in favor of the single up-front refusal. Per the First Principles review:error-code-baseline.jsonis reverted to base (the diff removes two uncodedunknown slotresponses and adds two -- net zero -- so no regeneration is needed), and the single-consumer_resolve_mode_slot()helper is inlined at its call site.Tests
test/test_chat_mode_security.py-- 16 tests:trust_reads/trust/normalon an unknown slot answer400 unknown slotand never calldeactivate.[],{},0,False) ontrust/trust_readsanswer400and do not widen (addresses the GPT 5.6 review back-door finding).trust/trust_readsdo not revoke an active grant (the fix(dashboard): stop a per-slot mode change revoking the global YOLO grant #4416 x api_chat_mode: trust_reads widens on an unknown slot, rejected requests still mutate, deactivate blocks the loop #4454 interplay).deactivate()runs off the event loop.Regression --
test_trust_reads.py,test_channel_trust_revoke.py,test_dashboard_chat.py(785 passed; one pre-existingTestIsReadOnlyBashfailure reproduces onorigin/mainand is unrelated to this diff).test/test_error_code_contract.pypasses with the baseline at base.Manual verification
N/A -- unit coverage sufficient: the change is confined to one handler whose every branch is exercised directly by the new contract tests, including the SEL event path.
Screenshots / video
N/A -- no user-visible UI change.
Related Issues
Closes #4454
Checklist
fix(dashboard): ...)docs/system-specs/modules/security.mdTTL table corrected