Repository navigation
feat(agent-mesh): route require_approval through the action-bound coordinator (#3067) - #3076
Conversation
…rdinator When an approval_coordinator and approval_chain_id are configured on govern(), require_approval decisions are now routed through the merged ADR-0030 ApprovalCoordinator instead of the legacy approval-handler-only path. The decision is bound to the exact action via an ActionBinding digest, a request is opened against the configured chain, the existing ApprovalHandler supplies the approver vote as one authenticated stage-0 chain entry, and the request is revalidated immediately before execution. Anything short of a terminal allow over the same action digest, policy version, and chain version denies fail-closed: an unpermitted approver identity, an expired request (TTL), or a rejection. Audit entries carry the action digest, approver, policy version, and the policy-decision / approval-request / approval-resolution ids (ADR-0030 section 7), reusing the existing AuditEntry assurance fields. The legacy path is unchanged when no coordinator is configured. No changes to the approval_protocol foundation package. 8 new tests; full govern/governance/approval suites green. Refs microsoft#3067, microsoft#2478
🤖 AI Agent: security-scanner — View details
No security issues found. |
🤖 AI Agent: code-reviewer — View details
TL;DR: 0 blockers, 1 warning. The PR introduces a robust ADR-0030 implementation but has a minor test coverage gap.
Action items:
| Warnings: fine as follow-up PRs. | |
🤖 AI Agent: breaking-change-detector — API Compatibility
API Compatibility
|
🤖 AI Agent: docs-sync-checker — Docs Sync
Docs Sync
|
🤖 AI Agent: test-generator — `agentmesh/governance/govern.py`
|
PR Review Summary
Verdict: AI review comments are untrusted advisory output. The summary reports workflow-generated completion status only, not model-authored pass/fail claims. |
Imran Siddique (imran-siddique)
left a comment
There was a problem hiding this comment.
Solid ADR-0030 implementation. The coordinator path is fail-closed on both TTL expiry and unpermitted identities, the action digest binds to the full parameter set (tamper-evident), and the audit entries carry all required protocol IDs. Legacy path unchanged when coordinator is not configured -- backward compat preserved. Test suite covers every critical branch. LGTM.
|
C:/Program Files/Git/rerun |
4ab1b87
into
microsoft:main
Ricky Gummadi (Ricky-G)
left a comment
There was a problem hiding this comment.
Reviewed and happy with this. The coordinator path is fail-closed on both timeout and unpermitted identities, the action digest binds the full parameter set, and the legacy path stays the default when no coordinator is configured, so existing users are unaffected. Imran Siddique (@imran-siddique) has already approved.
One housekeeping ask before merge: please add Closes #3067 to the description so the tracker closes automatically. The title references it, but the closing keyword needs to be in the body to take effect.
Good to merge once that is in.
|
Thanks Ricky Gummadi (@Ricky-G). Added |
…t#3083) Port Python agent-mesh approval_protocol subpackage to the TypeScript SDK, bringing require_approval chain execution on par with the Python reference from microsoft#3076 (ADR-0030): - approval-protocol/digest.ts: RFC 8785 JCS canonicalization (UTF-16 key sort, format integers without decimal) + SHA-256 action digests with "sha256:" prefix. Deterministic across key insertion order. - approval-protocol/binding.ts: ActionBinding + ActionTarget, bindingDigest binds the exact operation/agent/target/parameters so an approval for one binding can never authorize a different action. - approval-protocol/models.ts: PolicyDecisionRecord, ApprovalRequest, ApprovalChainEntry (with seal/verifyDigest for hash-linked integrity), ApprovalResolution; utcnow(), inputDigest(), presentedCanonical(). - approval-protocol/store.ts: ApprovalStore interface + InMemoryApprovalStore; consume() is atomic and returns true exactly once. - approval-protocol/coordinator.ts: ApprovalCoordinator with openRequest, submitEntry (authority-checked, idempotent by chainEntryId, advisory entries never satisfy a stage), validateForExecution (pre-execution revalidation: digest/version/chain-integrity checks, one-time consume, fail-closed on any unexpected error), and _maybeResolve (single deny terminates immediately; all required stages must allow). - 31 new tests covering the JCS serializer, binding digest, coordinator lifecycle, chain integrity, consume-once, expiry, digest mismatches, unpermitted identity, advisory vote behavior, and idempotent resubmission. Semantic contract matches the Python reference. Node.js is single-threaded so InMemoryApprovalStore needs no mutex (parity with Python's RLock is not needed in this runtime). Closes microsoft#3083 Signed-off-by: Varun Nuthalapati <nuthalapativarun@gmail.com>
Summary
Step 2 of the ADR-0030 rollout (issue #3067, follows the merged foundation #3015): route
require_approvalpolicy decisions through the action-boundApprovalCoordinatoringovern().Until now
require_approvalwent straight to the legacyapproval.pyhandler (synchronous approve/deny, no action binding, no audit linkage, post-hoc timeout). This PR wires it through the merged ADR-0030 coordinator while keeping the legacy path as the default.How it works
When both
approval_coordinatorandapproval_chain_idare set ongovern()/GovernanceConfig, arequire_approvaldecision:ActionBinding(operation, agent, tool, parameters, subject) and its SHA-256 / JCS digest;ApprovalHandleras the synchronous source of the approver vote, recorded as one authenticated stage-0 chain entry;validate_for_execution): the action digest, policy version, and chain version must all still match, and the approval is consumed exactly once.Anything short of a terminal allow denies, fail-closed:
approval_ttl_seconds),Audit entries for the decision carry the action digest (
arguments_hash), approver (approver_did), policy version, and thepolicy_decision_id/approval_request_id/approval_resolution_id(ADR-0030 section 7), reusing the existingAuditEntryassurance fields.Scope and deferred work
approval_protocolfoundation package (kept separate, per the issue).Tests
tests/test_govern_approval_coordinator.py(8 tests): approve runs the tool; reject denies; an unpermitted identity denies; zero-TTL denies (fail-closed timeout); audit linkage carries the protocol ids; the action digest is bound to parameters; non-approval actions are unaffected; the legacy path still works without a coordinator. Full govern / governance / approval_protocol suites green (100 passed).Closes #3067.
Refs #2478.