Skip to content

feat(typescript): action-bound approval protocol parity (TypeScript SDK)#3200

Open
nuthalapativarun wants to merge 1 commit into
microsoft:mainfrom
nuthalapativarun:feat/3083-typescript-approval-chain
Open

feat(typescript): action-bound approval protocol parity (TypeScript SDK)#3200
nuthalapativarun wants to merge 1 commit into
microsoft:mainfrom
nuthalapativarun:feat/3083-typescript-approval-chain

Conversation

@nuthalapativarun

Copy link
Copy Markdown
Contributor

Description

Adds TypeScript parity for the action-bound approval protocol (ADR-0030), as tracked in #3083.

The Python reference implementation landed in #3076 (routing require_approval through the ApprovalCoordinator) plus the underlying approval_protocol subpackage. This PR brings the same approval-chain execution layer to the TypeScript SDK. One PR per SDK per the pattern established in prior parity efforts.

What this adds (agent-governance-typescript/src/approval-protocol/):

  • digest.ts — RFC 8785 JCS canonicalization (object keys sorted by UTF-16 code unit, integers without decimal point) + sha256Jcs for action digests. Deterministic across key insertion order.
  • binding.tsActionBinding / ActionTarget / bindingDigest. An approval for one binding can never authorize a different action: change a parameter, the target, the tool schema version, or the acting agent, and the digest changes.
  • models.tsPolicyDecisionRecord, ApprovalRequest, ApprovalChainEntry (with sealEntry/verifyEntryDigest for hash-linked chain integrity), ApprovalResolution; inputDigest, presentedCanonical.
  • store.tsApprovalStore interface + InMemoryApprovalStore. consume() is atomic (one-time-use guard, ADR-0030 section 6).
  • coordinator.tsApprovalCoordinator with three public methods:
    • openRequest: binds a require_approval decision to a durable, TTL-bounded request
    • submitEntry: authority-checked (by identity or role), idempotent by chainEntryId, advisory (llm_advisory) entries never satisfy a stage, single deny terminates immediately
    • validateForExecution: pre-execution revalidation — checks action digest, policy version, chain version, chain integrity, expiry, and consume-once; fails closed on any unexpected error

All symbols re-exported from src/index.ts.

Semantic contract matches the Python reference precisely. Node.js is single-threaded so InMemoryApprovalStore does not need a mutex (threading.RLock is not needed in this runtime — idiomatic adaptation per @imran-siddique's guidance).

Type of Change

New feature — language parity

Package(s) Affected

agent-governance-typescript

Checklist

  • Tests pass (npm test — 31 new tests, 591 total, all green)
  • Lint passes (npm run lint)
  • Build passes (npm run build)
  • All commits signed with DCO (-s)
  • No secrets, tokens, or credentials included
  • No CI/CD config changes

Attribution & Prior Art

Python reference implementation: agent-governance-python/agent-mesh/src/agentmesh/governance/approval_protocol/ (coordinator + models + binding + digest + store). Python wiring into govern() landed in #3076 by @carloshvp. TypeScript port mirrors the Python semantics; no new design.

AI Assistance

I can explain every change. Tests were run locally. Not autonomously submitted.

IP, Patents, and Licensing

All new code is original and placed under the MIT License, consistent with the existing SDK. No third-party libraries added.

Related Issues

Closes #3083

…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>
@github-actions github-actions Bot added tests size/XL Extra large PR (500+ lines) labels Jun 28, 2026
@github-actions

Copy link
Copy Markdown
🤖 AI Agent: test-generator — `agent-governance-typescript/src/approval-protocol/binding.ts`

AI-generated review output. Treat it as untrusted analysis and verify before acting.

agent-governance-typescript/src/approval-protocol/binding.ts

  • test_makeActionTarget_with_partial_options -- Validate that makeActionTarget correctly handles partial options and defaults resource to null.
  • test_bindingDigest_uniqueness -- Ensure bindingDigest generates unique digests for different ActionBinding inputs.

agent-governance-typescript/src/approval-protocol/coordinator.ts

  • test_openRequest_with_unknown_chain -- Verify openRequest throws ApprovalProtocolError for unknown chainId.
  • test_submitEntry_with_unauthorized_identity -- Ensure submitEntry throws ApprovalProtocolError if the identity is not authorized for the stage.
  • test_validateForExecution_with_action_digest_mismatch -- Test that validateForExecution returns allowed: false with ReasonCode.ACTION_DIGEST_MISMATCH when currentActionDigest does not match.
  • test_validateForExecution_with_expired_request -- Verify validateForExecution denies execution with ReasonCode.EXPIRED for expired requests.
  • test_validateForExecution_with_consumed_request -- Ensure validateForExecution denies execution with ReasonCode.ALREADY_CONSUMED for consumed requests.

@github-actions

Copy link
Copy Markdown
🤖 AI Agent: breaking-change-detector — API Compatibility

AI-generated review output. Treat it as untrusted analysis and verify before acting.

API Compatibility

Severity Change Impact
High Introduction of new ApprovalCoordinator class with methods like openRequest, submitEntry, and validateForExecution that enforce strict validation and fail-closed behavior. Changes in the behavior of the approval process may cause existing integrations to break if they do not conform to the new validation rules.
High ApprovalStore interface includes a consume() method that is atomic and enforces a one-time-use guard. Existing implementations of ApprovalStore may break if they do not implement the new consume() method or fail to meet the atomicity requirement.
High bindingDigest function ensures that any change in action parameters, target, tool schema version, or acting agent results in a different digest. Existing systems relying on previous digest calculations may encounter mismatches.
Medium ApprovalCoordinator enforces stricter validation for action digests, policy versions, chain versions, and chain integrity during execution validation. Systems that do not adhere to these stricter validations may fail during execution.
Medium ApprovalCoordinator enforces fail-closed behavior for all failure paths, including unexpected errors. This may lead to previously successful operations being denied if they encounter unexpected errors.

@github-actions

Copy link
Copy Markdown
🤖 AI Agent: security-scanner — View details

AI-generated review output. Treat it as untrusted analysis and verify before acting.

No security issues found.

@github-actions

Copy link
Copy Markdown
🤖 AI Agent: code-reviewer — Action items:

AI-generated review output. Treat it as untrusted analysis and verify before acting.

TL;DR: 0 blockers, 1 warning. The implementation appears robust and aligns with the Python reference, but a potential issue with hash-linked chain integrity verification should be reviewed.

# Sev Issue Where
1 Warn Potential gap in hash-linked chain integrity verification for ApprovalChainEntry. coordinator.ts

Action items:

  • None.

Warnings (fine as follow-up PRs):

# Issue Where
1 Ensure verifyEntryDigest is consistently applied to validate the integrity of the hash-linked chain in submitEntry and validateForExecution. coordinator.ts

@github-actions

Copy link
Copy Markdown
🤖 AI Agent: docs-sync-checker — Docs Sync

AI-generated review output. Treat it as untrusted analysis and verify before acting.

Docs Sync

  • agent-governance-typescript/src/approval-protocol/binding.ts -- missing docstrings for makeActionTarget, makeActionBinding, bindingToCanonical, and bindingDigest.
  • agent-governance-typescript/src/approval-protocol/coordinator.ts -- missing docstrings for ApprovalProtocolError, ReasonCode, ExecutionDecision, makeApprovalStage, stageAuthorizes, getStage, ApprovalCoordinator, openRequest, submitEntry, and validateForExecution.
  • README.md -- no updates found for the new approval-protocol module or its components.
  • CHANGELOG.md -- missing entry for the addition of the approval-protocol module and its new features.

@github-actions

Copy link
Copy Markdown

PR Review Summary

Check Status Details
🔍 Code Review ⚠️ Missing No current-run comment
🛡️ Security Scan ⚠️ Missing No current-run comment
🔄 Breaking Changes ⚠️ Missing No current-run comment
📝 Docs Sync ⚠️ Missing No current-run comment
🧪 Test Coverage ⚠️ Missing No current-run comment

Verdict: ⚠️ AI review incomplete; ready for human review

AI review comments are untrusted advisory output. The summary reports workflow-generated completion status only, not model-authored pass/fail claims.

@github-actions

Copy link
Copy Markdown

🟡 Contributor Check: MEDIUM

Check Result
Profile MEDIUM
Credential LOW
Overall MEDIUM

Automated check by AGT Contributor Check.

@github-actions github-actions Bot added the needs-review:MEDIUM Contributor check flagged MEDIUM risk label Jun 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-review:MEDIUM Contributor check flagged MEDIUM risk size/XL Extra large PR (500+ lines) tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: language parity for require_approval approval chains (TypeScript, .NET, Rust, Go)

1 participant