Repository navigation
Conversation
Apply the existing access policy before protected root agents or orchestrators resolve prompts, call models, or execute tools. Fail closed when the access plugin is missing, emit refusals through the stream sink, and recheck access during tool-approval replay. Add HTTP and engine regressions plus access-policy documentation. Fixes #151
| # same policy before entering either kind of protected executor. | ||
| candidates = [node.node] | ||
| for route_filter in filters: | ||
| candidates = route_filter.filter(state.get("run_context", {}), candidates) |
There was a problem hiding this comment.
On resume, this reads the run_context saved in the original checkpoint instead of the approver’s current verified principal.
I reproduced a user starting with role=admin, losing that role before approval, and the tool still running because the old role remains in state.
This means role/scope revocation is not enforced; the resumed check needs fresh, verified authorization context.
Resolve the task-index conflict while retaining protected-root and upstream task entries. Verified the combined tree with make check (1,498 tests).
Carry the current verified principal through both approval ports and use its request-local permission facts for protected root and child checks. Do not inherit checkpointed roles, scopes, organization or metadata. Validate caller/run/session consistency before claiming the approval and keep credentials out of graph projections. Add role revocation, missing context, permission facts, ownership and concurrent resume regressions. Document the additive Python port keyword. Fixes #151
| caller_user_id: str | None = None, | ||
| caller_session_id: str | None = None, | ||
| access_token: str | None = None, | ||
| context: RunContext | None = None, |
There was a problem hiding this comment.
agentctl.chat._resolve_local_approvals() still calls this port without context, even though it already receives the current RunContext.
I reproduced a protected root allowed by role=admin pausing for approval; choosing allow in local chat fails with ApprovalInvocationMismatch because resume sees no roles.
Please forward the context there and cover both local stream and non-stream paths, otherwise this regresses local HITL for context-based policies.
Pass the local chat RunContext through the approval port so protected roots retain current role, scope and metadata facts in both console modes. Add real-engine regressions for allowed and revoked permissions without exposing credentials or weakening fail-closed replay checks.
Protected root agents and orchestrators could execute even when the access resolver denied access, because filtering only covered child delegation. Apply the existing policy before entering a protected root executor, preventing prompt resolution, model calls and tool execution on denial. Missing access plugins also fail at startup for direct Python callers.
Denied new runs return
Access denied.with an empty route and emit the refusal through the existing streaming answer sink.Approval replay now uses the current verified decision request's authorization facts. The manager supplies a fresh
RunContexton both approval paths; root entry replaces the execution-local context for root and child checks instead of reading saved grants from the checkpoint. Revoked roles/scopes/organization/metadata and omitted fresh permission facts cannot inherit the original grant. Caller/run/session conflicts are rejected before claiming the approval. The reviewed tool request and completed replay steps remain bound to the checkpoint.Local chat also forwards its host-supplied
RunContextwhen approving a tool in both streaming and non-streaming console modes. Current role/scope/metadata facts reach replay; changing a permission at the approval prompt still prevents the tool effect.Compatibility:
resume/resume_streamgain an optionalcontext: RunContext | Nonekeyword. External implementations of the optional approval ports must accept it; hosts must supply trusted current facts. ADR 0002 records the contract.mainis merged and the task-index conflict is resolved.Validation (2026-10-24):
make check: 1,546 tests passed; formatting (363 files), lint, mypy (359 files) and generated-stub checks passed, with 27 dependency warnings.make validateandagentctl validate examples/whatsapp-pilot/agents.yml: all three examples passed.git diff --check: passed.Fixes #151