Repository navigation
Conversation
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 2 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ SSOT Configuration Compliance: Passing🎉 No new hardcoded values of either class — Known backlog in |
|
Security review (Opus) at 428598b: blocked. Nothing is exploitable through today's sources, but these must be settled first:
Verified fine:
|
|
Review fixes pushed (head 8e0e123): atomic decision claim (one conditional UPDATE ... RETURNING; the loser matches no row and does not resume; concurrent approve/approve and approve/reject tests on Postgres), owner-scoped pending list (new nullable |
|
Security delta review (Opus) at 8e0e123: approve on everything except the migration renumber. The renumber stays deferred: 098's Verified:
Conditions and LOWs:
|
Thinking Path
#13421 folds seven approval surfaces into one record.
approvalsis already the canonical table (#17043), so S1 extends it with nullable columns rather than adding a record type, and adds the single risk ladder and the inbox query the frontend slice (S3) builds on. Owner decisions of 2026-10-12 are followed as recorded on the issue.What Changed
models/approval.py: nullablesource,risk_tier,expires_at,payload_hash,resume_ref;ApprovalSourceenum (terminal_command, agent_tool, workflow_plan, plugin_capability, autoresearch, skill_governance, company, mcp_tool_schema).20261012_098(after the single head20260928_097): adds the five columns plus two indexes; asserts row count unchanged and every new column NULL (the 094 pattern); downgrade refuses once any row carries a value in one of them.20261012_099(found on the way, see below): adds the missingtask_approval_links.created_at.autobot_shared/risk_tier.py:RiskTier(low|medium|high|critical, asserted to be a subset ofSeverityvalues),risk_tier_from_severity,risk_tier_from_command_risk,parse_risk_tier(accepts the terminal's uppercase andcommand_execution.RiskLevelby member name). Grepped first: no existing approval tier.Severityis not widened;UNKNOWNraises instead of guessing; DANGEROUS/FORBIDDEN map to critical.services/approval_execution.py:register_resume_handler/resume_decided_approval, keyed bysource, run after every decision (approve, reject, revision) whenresume_refis set; failures are recorded like bug(approvals): an approved action that fails or has no handler leaves only a log line, while the approval still reads APPROVED #17141, never raised.services/approval_gate_service.py:create_approvaltakes keyword-only record fields validated by the newservices/approval_record_fields.py(sourced approval must be graded;resume_refneeds a registered handler;expires_ataware and future;payload_hashdefaults to sha256 of canonical context);_transitionresumes throughapproval_execution;list_pendingis the inbox query (all sources, unscoped rows only, so no company-tenant leakage).api/approval_gates.py:GET /approval-gates/pendingplussource/risk_tierfilters on the list route; response carries all five fields. Schemas moved to newapi/schemas_approvals.pybecauseschemas_workflows.pymay not grow (ceilings lowered in both records, 3011 to 2917).store_authority:approvalconcept registered (Postgres is the record).autobot-frontend/src/types/generated/api.tsregenerated with the CI recipe (separate commit, diff is approval-only: +86/-3).Security choices: the HTTP create route does NOT accept
source,risk_tier,resume_ref,expires_atorpayload_hash(tested): a caller-chosen source would let any user pose as the terminal, and a caller-chosenresume_refwould pick what the server resumes. Only server-side emitters set them.Defect found and fixed here: on a freshly migrated database
selectinload(Approval.task_links)(used bylist_approvalsandlist_pending) failed withcolumn task_approval_links.created_at does not exist; migration 099 fixes it. The same drift on seven other tables is filed once as #18392, not patched here.For S2 (emitters), recorded as asked
chat_workflow/approval_baseline.pyon main (refactor(tools): one tool-effect catalogue, every mutating tool gated by category with an SLM-only relaxation (#18294) #18310): baseline categories are ALL valid categories minus those the SLM settingchat.relaxed_approval_categoriesrelaxes; callers can only add (union_categories), never remove; SLM unreachable or malformed relaxes nothing (fail closed). S2e (agent tool emitter) must take its gate set frombaseline_approval_categories()and must not offer a per-session or per-approval way to lift a category.contextand the inbox needs a session-ownership filter (THREAT_MODEL section 2) before those sources are shown to non-owners. Not done in S1 because no emitter sets a session yet.expires_atis stored and published, not enforced: nothing moves a stale pending row to EXPIRED yet.store_authorityapprovaldeclares no Redis projection; S2a must add the terminal pending projection with its rebuild, per the note on the entry.services/approval_gate_service.pyglobal-channel publish baseline entry 388 to 429 (same pre-existing finding, security: approval and checkpoint notifications broadcast workflow/session ids on 'global' #17373).Verification
alembic upgrade):test_approval_record_columns_098.py+test_approval_inbox_query_13421.py: 7 passed (rows untouched, round trip, refusal, inbox query across sources, resume through the real table).risk_tier_test.py29,approval_record_test.py19,approval_gates_inbox_13421_test.py7: 55 passed; existing approval suites (execution, proposer, action validation, orphan chain, human decider, gate service, global-channel baseline) pass.AUTOBOT_PREPUSH_ALLOW_TIMEOUT=1. The only frontend change is the generatedapi.ts.alembic heads: single head20261012_099.Model Used
Claude Sonnet 5.5
Single-issue rationale: S1 of the multi-slice #13421 is the schema every later slice (S2a-e, S3) builds on and it must merge first; the slices are sequenced by design, so none can ride with it.
Refs #13421
🤖 Generated with Claude Code