Repository navigation
feat: offline-verifiable decision receipts (Ed25519 + JCS) - #1519
Imran Siddique (imran-siddique) merged 6 commits into
Conversation
- Add parent_receipt_hash for per-tool-call hash chaining - Enforce RFC 8785 JCS canonical JSON (ensure_ascii=False) - Add verify_receipt_chain() for offline chain verification - Add to_slsa_provenance() for SLSA v1.0 predicate emission - Add CLI verifier (scripts/verify_receipts.py) - Add tutorial (docs/tutorials/33-offline-verifiable-receipts.md) - 65 tests passing Closes microsoft#1499
- Fix CodeQL high: use urlparse hostname check instead of substring match for builder URL validation (Incomplete URL substring sanitization) - Fix critical: verify_receipt_chain now flags unsigned receipts instead of silently skipping them, preventing unsigned receipt injection - Update tests to verify the unsigned receipt detection behavior
|
Welcome to the Agent Governance Toolkit! Thanks for your first pull request. |
There was a problem hiding this comment.
🤖 AI Agent: code-reviewer
Pull Request Review: Offline-Verifiable Decision Receipts (Ed25519 + JCS)
🔴 CRITICAL: Security Issues
-
Replay Attack Vector in Hash Chaining:
- The
parent_receipt_hashmechanism ensures hash-chain integrity but does not prevent replay attacks. An attacker could replay a valid receipt chain in a different context without detection. - Recommendation: Include a session-specific nonce or identifier in the receipt payload to bind the chain to a specific execution context.
- The
-
Unsigned Receipts:
- The
verify_receipt_chainfunction flags unsigned receipts but does not enforce fail-closed behavior. Unsigned receipts could bypass verification in certain scenarios. - Recommendation: Enforce fail-closed behavior by rejecting chains with unsigned receipts outright. Update the
verify_receipt_chainfunction to raise an exception or return a critical error code when encountering unsigned receipts.
- The
-
Signature Verification:
- The
verify_receiptfunction does not validate the authenticity of thesigner_public_key. An attacker could replace thesigner_public_keyin a receipt with their own key and provide a valid signature. - Recommendation: Implement a mechanism to validate the
signer_public_keyagainst a trusted source (e.g., a certificate authority or a pre-shared key registry).
- The
-
Canonicalization and Unicode Handling:
- While the implementation adheres to RFC 8785 for JSON canonicalization, the use of
ensure_ascii=Falsecould introduce vulnerabilities if the Unicode handling is not thoroughly tested against edge cases (e.g., surrogate pairs, invalid UTF-8 sequences). - Recommendation: Add tests for edge cases in Unicode handling to ensure compliance with RFC 8785 and prevent potential encoding-related attacks.
- While the implementation adheres to RFC 8785 for JSON canonicalization, the use of
🟡 WARNING: Breaking Changes
- Public API Changes:
- The addition of
verify_receipt_chainto the public API (__init__.py) is a breaking change for users who rely on the previous API structure. While this change is beneficial, it should be clearly documented in the release notes.
- The addition of
💡 Suggestions for Improvement
-
Thread Safety:
- The
ReceiptStoreclass uses a list (self._receipts) to store receipts, but there is no explicit synchronization mechanism for concurrent access. This could lead to race conditions in multi-threaded environments. - Recommendation: Use thread-safe data structures like
queue.Queueor add locks to ensure thread-safe operations onself._receipts.
- The
-
Error Reporting:
- The
verify_receipt_chainfunction returns a list of error strings. While this is useful for debugging, it may be better to raise structured exceptions or return a structured object containing both errors and metadata about the verification process. - Recommendation: Refactor
verify_receipt_chainto return a structured result object or raise specific exceptions for better integration into automated workflows.
- The
-
Documentation:
- The new tutorial (
33-offline-verifiable-receipts.md) is a great addition, but it should include a section on the security implications of using the receipt chain, especially regarding replay attacks and unsigned receipts. - Recommendation: Expand the tutorial to include best practices for secure receipt handling and verification.
- The new tutorial (
-
Backward Compatibility:
- While the changes appear to be backward-compatible, the addition of
parent_receipt_hashto theGovernanceReceiptclass may impact users who rely on the previous receipt structure. - Recommendation: Document this change in the release notes and provide migration guidance for users.
- While the changes appear to be backward-compatible, the addition of
-
CLI Tool Enhancements:
- The
verify_receipts.pyscript provides useful functionality but lacks options for detailed output (e.g., JSON-formatted results for integration into CI/CD pipelines). - Recommendation: Add an option to output verification results in JSON format for easier integration into automated workflows.
- The
-
Test Coverage:
- While the test coverage is extensive, consider adding tests for edge cases in Unicode handling and malformed receipt chains (e.g., cyclic chains, missing receipts).
- Recommendation: Expand test cases to cover edge scenarios and ensure robustness.
Summary
The pull request introduces a robust mechanism for offline-verifiable decision receipts, leveraging Ed25519 signatures, RFC 8785 JCS canonicalization, and hash chaining. While the implementation is well-structured and adheres to relevant standards, there are critical security concerns related to replay attacks, unsigned receipts, and signature verification. Addressing these issues is essential to ensure the security and reliability of the receipt mechanism.
Action Items:
- Implement session-specific nonce or identifier to prevent replay attacks.
- Enforce fail-closed behavior for unsigned receipts in
verify_receipt_chain. - Validate
signer_public_keyagainst a trusted source during signature verification. - Add tests for Unicode edge cases and malformed receipt chains.
- Document breaking changes and provide migration guidance.
- Enhance the CLI tool with JSON output for CI/CD integration.
🤖 AI Agent: contributor-guide — Welcome to the Microsoft Agent Governance Toolkit project! 👋Welcome to the Microsoft Agent Governance Toolkit project! 👋Hi there, and welcome to the community! 🎉 Thank you so much for taking the time to contribute to the project. We’re thrilled to have you here, and we appreciate the effort you’ve put into this pull request. It’s always exciting to see new contributors join the project and bring fresh ideas to the table. What You Did Well 🌟
Suggestions for Improvement 🛠️While this is a strong contribution, there are a few areas where we can make it even better:
Next Steps 🚀
Helpful Resources 📚
Thank you again for your contribution! If you have any questions or need further clarification, don’t hesitate to ask. We’re here to help and support you through the process. 😊 |
🤖 AI Agent: security-scanner — Security Review of PR: feat: offline-verifiable decision receipts (Ed25519 + JCS)Security Review of PR: feat: offline-verifiable decision receipts (Ed25519 + JCS)This PR introduces offline-verifiable decision receipts using Ed25519 signatures, RFC 8785 JSON Canonicalization Scheme (JCS), and optional SLSA provenance predicates. It also adds a hash-chaining mechanism for receipts to ensure integrity and detect tampering. Below is a detailed security review of the changes. Findings1. Prompt Injection Defense Bypass
2. Policy Engine Circumvention
3. Trust Chain Weaknesses
4. Credential Exposure
5. Sandbox Escape
6. Deserialization Attacks
7. Race Conditions
8. Supply Chain
Summary of Findings
General Recommendations
This PR introduces critical functionality for offline-verifiable decision receipts, which is a significant improvement for auditability and security. However, the identified issues, particularly around policy evaluation and trust chain validation, must be addressed to ensure the robustness of the implementation. |
- Add session_id to GovernanceReceipt to prevent replay attacks by binding receipts to a specific execution context (Critical #1) - Add trusted_keys parameter to verify_receipt_chain for signer public key validation against a trusted set (Critical microsoft#3) - Add Unicode edge case tests: emoji, CJK, empty strings (Critical microsoft#4) - Add --json output flag to verify_receipts.py for CI/CD integration - 74 tests passing (9 new tests added)
There was a problem hiding this comment.
🤖 AI Agent: code-reviewer
Pull Request Review: feat: offline-verifiable decision receipts (Ed25519 + JCS)
🔴 CRITICAL: Security Issues
-
Missing Replay Attack Mitigation:
- The
verify_receipt_chain()function does not validate the uniqueness ofreceipt_idacross the chain. This omission could allow replay attacks where a malicious actor reuses a valid receipt from a previous session. - Action: Add a check to ensure all
receipt_idvalues in the chain are unique.
- The
-
Untrusted Key Handling:
- In
verify_receipt_chain(), receipts signed by untrusted keys are flagged but not explicitly rejected. This could lead to ambiguous behavior in downstream systems relying on the verification result. - Action: Ensure that receipts signed by untrusted keys are treated as invalid and explicitly fail the chain verification.
- In
-
Fail-Closed Enforcement:
- The
govern_tool_call()method enforces fail-closed behavior when receipt signing fails. However, the error message (receipt.error = f"signing_failed: {type(exc).__name__}") is not propagated to the caller, which could lead to silent failures. - Action: Raise an exception or return a clear error code when signing fails.
- The
-
Canonicalization Ambiguity:
- The
canonical_payload()method usesensure_ascii=Falseto comply with RFC 8785, but this behavior is not explicitly tested for edge cases like surrogate pairs or invalid Unicode sequences. - Action: Add tests for edge cases in Unicode handling to ensure compliance with RFC 8785.
- The
🟡 WARNING: Potential Breaking Changes
-
Public API Changes:
- The addition of
parent_receipt_hashandsession_idtoGovernanceReceiptchanges the canonical payload structure. This could break compatibility with systems relying on the previous payload format. - Action: Provide clear migration guidance in the documentation and consider versioning the canonical payload schema.
- The addition of
-
Exported Functionality:
- The new
verify_receipt_chain()function is exported viamcp_receipt_governed/__init__.py. If downstream consumers rely on the previous set of exports, this could cause compatibility issues. - Action: Ensure backward compatibility by documenting the new function and its intended use.
- The new
💡 Suggestions for Improvement
-
Thread Safety:
- The
ReceiptStoreclass is not thread-safe, which could lead to race conditions in concurrent environments. For example,self.store.add(receipt)ingovern_tool_call()assumes exclusive access to the store. - Action: Use thread-safe mechanisms like locks or concurrent data structures for
ReceiptStore.
- The
-
SLSA Provenance Validation:
- While the
to_slsa_provenance()method generates a valid SLSA predicate, there is no test to validate the generated output against the SLSA schema. - Action: Add schema validation tests for the SLSA predicate.
- While the
-
CLI Tool Output:
- The
verify_receipts.pyscript could benefit from more structured output, such as JSON logs for easier integration with CI/CD pipelines. - Action: Add a
--jsonflag to output structured results.
- The
-
Error Handling in CLI:
- The
verify_receipts.pyscript prints error messages directly to the console but does not return detailed error codes for CI/CD integration. - Action: Implement detailed error codes for different failure scenarios (e.g., signature failure, hash chain breakage).
- The
-
Test Coverage:
- While the test suite is extensive, it could benefit from additional tests for edge cases, such as:
- Receipts with missing fields.
- Invalid Unicode sequences in
canonical_payload(). - Large chains with thousands of receipts.
- Action: Expand test coverage to include these cases.
- While the test suite is extensive, it could benefit from additional tests for edge cases, such as:
-
Logging:
- The logging in
govern_tool_call()andverify_receipts.pycould be improved by including more context, such as thesession_idandreceipt_id. - Action: Enhance logging to include additional metadata for easier debugging.
- The logging in
-
Documentation:
- The new tutorial (
33-offline-verifiable-receipts.md) is comprehensive but could benefit from a section on common errors and troubleshooting tips. - Action: Add a troubleshooting section to the tutorial.
- The new tutorial (
Summary
This PR introduces a robust mechanism for offline-verifiable decision receipts, leveraging Ed25519 signatures, RFC 8785 JCS canonicalization, and hash chaining. While the implementation is generally solid, there are critical security issues that need to be addressed, particularly around replay attack mitigation and untrusted key handling. Additionally, potential breaking changes should be carefully documented, and thread safety should be improved for concurrent environments.
Priority Actions:
- Address replay attack mitigation and untrusted key handling (🔴 CRITICAL).
- Document migration paths for canonical payload changes (🟡 WARNING).
- Improve thread safety in
ReceiptStore(💡 SUGGESTION).
Once these issues are resolved, the feature will be ready for production deployment.
- CLI verify_receipts.py: structured per-receipt JSON output with exit codes (0=ok, 1=chain error, 2=load error) and --json flag detail - Tests: add Unicode edge cases (replacement char U+FFFD, Arabic RTL), SLSA schema field validation, inserted-receipt detection, and all-defaults unsigned receipt coverage (83 tests total)
There was a problem hiding this comment.
🤖 AI Agent: code-reviewer
🔴 CRITICAL: Security Issues
-
Missing Replay Attack Mitigation in
verify_receipt_chain:- The
verify_receipt_chainfunction checks for duplicatereceipt_idvalues but does not enforce uniqueness in theReceiptStoreitself. This leaves the system vulnerable to replay attacks if duplicate receipts are injected into the store before verification. - Recommendation: Enforce uniqueness of
receipt_idin theReceiptStore.add()method by checking for duplicates before appending to_receipts.
- The
-
Untrusted Receipt Signing Key Handling:
- The
verify_receipt_chainfunction allows unsigned receipts to pass with only a warning (⚠️ Unsigned receipt (no signature)), which could lead to security bypasses if an attacker inserts unsigned receipts into the chain. - Recommendation: Treat unsigned receipts as a critical error and fail verification. Update the
verify_receipt_chainfunction to enforce that all receipts must be signed.
- The
-
Weak Error Handling in Receipt Signing:
- The
sign_receiptfunction raises a genericRuntimeErrorwhen signing fails. This could result in unclear error messages and make debugging difficult. - Recommendation: Use a custom exception (e.g.,
ReceiptSigningError) to provide more context about the failure.
- The
-
Potential Key Spoofing in
verify_receipt_chain:- The
verify_receipt_chainfunction checks thesigner_public_keyagainst a trusted set but does not validate the format of the key. This could allow an attacker to inject malformed keys that bypass the check. - Recommendation: Validate the format of
signer_public_key(e.g., length and hex encoding) before comparing it to the trusted set.
- The
🟡 WARNING: Potential Breaking Changes
- Fail-Closed Enforcement in
govern_tool_call:- The updated
govern_tool_callmethod raises aRuntimeErrorif receipt signing fails. This is a change from the previous behavior, where the error was logged but execution continued. - Impact: This change may break existing integrations that rely on the previous behavior.
- Recommendation: Document this change clearly in the release notes and consider providing a configuration option to toggle between fail-closed and fail-open behavior.
- The updated
💡 Suggestions for Improvement
-
Thread Safety in
ReceiptStore:- While the
ReceiptStoreuses athreading.Lockfor thread safety, thequerymethod creates a snapshot of_receiptsand then performs filtering outside the lock. This could lead to race conditions if the store is modified concurrently. - Recommendation: Perform filtering directly within the locked section to ensure consistency.
- While the
-
Error Reporting in
verify_receipt_chain:- The error messages returned by
verify_receipt_chainare human-readable but lack structured metadata for programmatic consumption. - Recommendation: Include structured metadata (e.g., error codes) in the returned error list to facilitate automated analysis.
- The error messages returned by
-
Improved Logging in
verify_receipts.py:- The CLI tool logs verification results but does not provide detailed logs for debugging failed checks.
- Recommendation: Add an optional
--verboseflag to include detailed logs for each verification step.
-
Backward Compatibility for Unsigned Receipts:
- The stricter enforcement of signed receipts may break compatibility with older systems that emit unsigned receipts.
- Recommendation: Provide a configuration option to allow unsigned receipts for backward compatibility, with a clear warning about the security risks.
-
Unit Test Coverage for Edge Cases:
- While the tests cover many scenarios, edge cases like malformed JSON, invalid receipt fields, and corrupted signatures are not explicitly tested.
- Recommendation: Add unit tests for these edge cases to ensure robust handling.
-
Documentation Enhancements:
- The tutorial (
docs/tutorials/33-offline-verifiable-receipts.md) does not cover the implications of hash chaining and signature verification in detail. - Recommendation: Expand the tutorial to include security considerations, such as replay attack prevention and trusted key management.
- The tutorial (
Summary
This PR introduces significant improvements to the mcp-receipt-governed adapter, including offline-verifiable decision receipts with hash chaining, RFC 8785 JCS compliance, and SLSA provenance support. However, there are critical security issues related to replay attack mitigation, unsigned receipt handling, and key validation that must be addressed before merging. Additionally, the fail-closed behavior and stricter signature enforcement may introduce backward compatibility concerns.
- receipt.py: remove verbose docstrings; flatten to_slsa_provenance dict; tighten sign_receipt, verify_receipt, and verify_receipt_chain - adapter.py: collapse CedarPolicyEvaluator init; remove redundant comments; shorten govern_tool_call and govern_and_execute - verify_receipts.py: collapse _reconstruct and verify_chain; tighten main() - test_receipt.py: shared _make_chain helper; collapse unicode cases into one parametrized test; merge duplicate fixtures; 583 → 280 lines, same coverage
There was a problem hiding this comment.
🤖 AI Agent: code-reviewer
Pull Request Review: Offline-Verifiable Decision Receipts
This pull request introduces offline-verifiable decision receipts with hash chaining, RFC 8785 JCS compliance, and optional SLSA provenance support. Below is a detailed review of the changes:
🔴 CRITICAL: Security Issues
-
Signature Verification Fallback:
- The
verify_receiptfunction logs an error and returnsFalseif thecryptographylibrary is not available. This behavior could lead to silent failures in environments where the library is missing, potentially allowing unsigned or invalid receipts to pass unnoticed. - Actionable Recommendation: Raise an exception if the
cryptographylibrary is unavailable, as signature verification is critical for security.
- The
-
Receipt Signing Error Handling:
- In
McpReceiptAdapter.govern_tool_call, aRuntimeErroris raised if receipt signing fails. While this is a fail-closed approach, it would be safer to log the error and include the failed receipt in the store with an expliciterrorfield. This ensures that the failure is auditable. - Actionable Recommendation: Store the receipt with an
errorfield indicating the signing failure, and log the error for debugging purposes.
- In
-
Trusted Key Validation:
- The
verify_receipt_chainfunction optionally checks signer keys against atrusted_keyslist. However, the absence oftrusted_keysallows any signer to be trusted, which could lead to security bypasses in environments where key validation is expected. - Actionable Recommendation: Require
trusted_keysto be explicitly provided and fail validation if it isNone.
- The
-
Thread Safety:
- The
ReceiptStoreclass uses a threading lock (self._lock) for concurrent access. However, the lock is only applied in theMcpReceiptAdapter.govern_tool_callmethod, not in other methods likeaddorquery. This could lead to race conditions in multi-threaded environments. - Actionable Recommendation: Ensure all methods that modify or access shared state in
ReceiptStoreuse the threading lock.
- The
🟡 WARNING: Potential Breaking Changes
-
Public API Changes:
- The addition of
parent_receipt_hashandsession_idtoGovernanceReceiptchanges the canonical payload structure. This could break compatibility with existing systems that rely on the previous payload format. - Actionable Recommendation: Clearly document this change in the release notes and provide migration guidance for downstream users.
- The addition of
-
SLSA Provenance Emission:
- The new
to_slsa_provenancemethod introduces a dependency on the SLSA specification. If downstream systems are not prepared to handle this format, it could cause integration issues. - Actionable Recommendation: Make SLSA emission optional and clearly document its usage.
- The new
💡 Suggestions for Improvement
-
Error Reporting in
verify_receipt_chain:- The error messages returned by
verify_receipt_chaincould include more context, such as the receipt ID and session ID, to aid debugging. - Suggestion: Enhance error messages with additional context.
- The error messages returned by
-
Canonical JSON Serialization:
- The
canonical_payloadmethod usesensure_ascii=Falsefor UTF-8 compliance. Consider adding a test case to verify that non-ASCII characters are correctly serialized and hashed. - Suggestion: Add tests for non-ASCII characters in receipt fields.
- The
-
Logging Enhancements:
- The logging in methods like
sign_receiptandverify_receiptcould include more details, such as the receipt ID and signer public key, to improve traceability. - Suggestion: Enhance logging with receipt-specific details.
- The logging in methods like
-
Documentation:
- The new
verify_receipt_chainfunction is a critical addition but lacks detailed documentation in the tutorial. Include examples of its usage and explain the implications of trusted key validation. - Suggestion: Update the tutorial to cover
verify_receipt_chainin detail.
- The new
-
Test Coverage:
- While the pull request adds 25 new tests, ensure edge cases are covered, such as:
- Receipts with missing fields (e.g.,
parent_receipt_hash). - Invalid UTF-8 characters in receipt fields.
- Large receipt chains to test performance and scalability.
- Receipts with missing fields (e.g.,
- Suggestion: Expand test coverage for edge cases.
- While the pull request adds 25 new tests, ensure edge cases are covered, such as:
Summary
This pull request significantly enhances the security and verifiability of governance receipts. However, it introduces critical security risks related to signature verification fallback, trusted key validation, and thread safety. Addressing these issues is essential to ensure the robustness of the implementation. Additionally, potential breaking changes should be documented, and improvements to error reporting, logging, and test coverage are recommended.
Overall Rating: Needs improvement before merging.
- verify_receipt: raise ImportError instead of silently returning False when cryptography library is missing - ReceiptSigningError: custom exception replaces generic RuntimeError in govern_tool_call for clearer failure context - ReceiptStore.add: enforce receipt_id uniqueness to prevent replay injection - verify_receipt_chain: validate signer_public_key is 64-char hex before trusted-key comparison to block malformed key bypass
There was a problem hiding this comment.
🤖 AI Agent: code-reviewer
Review Summary
This pull request introduces offline-verifiable decision receipts with Ed25519 signatures and RFC 8785 JCS canonical JSON compliance. It also adds hash chaining for receipt integrity and optional SLSA provenance emission. The implementation appears well-thought-out and includes extensive testing and documentation. However, there are critical security concerns, potential breaking changes, and areas for improvement.
🔴 CRITICAL: Security Issues
-
Receipt Signing Failures Are Not Fail-Safe
- In
McpReceiptAdapter.govern_tool_call, ifsign_receiptfails, the error is logged, but the receipt is still added to the store. This creates a potential security bypass where unsigned receipts are stored and could be mistaken for valid ones later.
Recommendation: Do not add unsigned receipts to the store. Raise an exception and fail the tool call entirely.
if self._signing_key: try: sign_receipt(receipt, self._signing_key) except Exception as exc: _logger.error(f"Receipt signing failed: {type(exc).__name__}") raise ReceiptSigningError( f"Receipt signing failed for tool={tool_name}: {type(exc).__name__}: {exc}" ) from exc
- In
-
No Validation of Trusted Public Keys in
verify_receipt_chain- The
verify_receipt_chainfunction acceptstrusted_keysbut does not enforce that all receipts are signed by a trusted key. This allows an attacker to inject receipts signed by untrusted keys into the chain.
Recommendation: Add a check to ensure that each receipt'ssigner_public_keyis in thetrusted_keysset if provided.
if trusted_set and r.signer_public_key not in trusted_set: errors.append(f"[{i}] Receipt signed by untrusted key: {r.signer_public_key}")
- The
-
Potential Replay Attack in Receipt Chain Verification
- The
verify_receipt_chainfunction checks for duplicatereceipt_idbut does not validate the uniqueness ofparent_receipt_hashacross the chain. This could allow an attacker to replay a receipt chain by reusing parent hashes.
Recommendation: Add a check to ensure thatparent_receipt_hashvalues are unique across the chain.
seen_hashes: set = set() for i, r in enumerate(receipts): if r.parent_receipt_hash in seen_hashes: errors.append(f"[{i}] Duplicate parent_receipt_hash {r.parent_receipt_hash} — possible replay attack") seen_hashes.add(r.parent_receipt_hash)
- The
🟡 WARNING: Potential Breaking Changes
-
ReceiptSigningErrorException- The introduction of the
ReceiptSigningErrorexception changes the behavior ofMcpReceiptAdapter.govern_tool_call. Previously, signing failures did not raise exceptions, but now they do. This could break existing code that relies on the method not raising exceptions.
Recommendation: Document this change clearly in the release notes and consider providing a backward-compatible mode.
- The introduction of the
-
Changes to
GovernanceReceiptSchema- The addition of
parent_receipt_hashandsession_idfields changes the schema ofGovernanceReceipt. This could break downstream consumers of theto_dict()method or serialized receipts.
Recommendation: Document these changes clearly in the release notes and provide migration guidance for downstream users.
- The addition of
💡 Suggestions for Improvement
-
Thread Safety in
ReceiptStore- While
ReceiptStoreuses a threading lock (self._lock), the lock is not used consistently across all methods. For example,query()andget_stats()do not acquire the lock before accessingself._receipts.
Recommendation: Ensure all methods that access or modifyself._receiptsacquire the lock.
def query(self) -> List[GovernanceReceipt]: with self._lock: return list(self._receipts)
- While
-
Error Handling in
verify_receipt- The
verify_receiptfunction catches all exceptions but does not log the error details. This could make debugging difficult.
Recommendation: Log the exception details before returningFalse.
except Exception as exc: _logger.error(f"Receipt verification failed: {type(exc).__name__}: {exc}") return False
- The
-
Improve Documentation for
verify_receipt_chain- The function's docstring is incomplete and does not explain the security implications of hash chaining or trusted key validation.
Recommendation: Expand the docstring to include details about the security checks performed and their importance.
- The function's docstring is incomplete and does not explain the security implications of hash chaining or trusted key validation.
-
Canonical JSON Serialization
- The
canonical_payloadmethod usesjson.dumpswithensure_ascii=False, which is correct for RFC 8785 compliance. However, consider adding a comment explicitly referencing RFC 8785 §3.2.2.2 for clarity.
- The
-
SLSA Provenance Emission
- The
to_slsa_provenancemethod is a valuable addition, but it assumes specific semantics forresolvedDependencies. Consider documenting these assumptions in the method docstring.
- The
Conclusion
The feature is well-implemented and aligns with security best practices, but the identified critical issues must be addressed before merging. Additionally, the potential breaking changes should be documented, and the suggested improvements can enhance the robustness and clarity of the implementation.
Imran Siddique (imran-siddique)
left a comment
There was a problem hiding this comment.
Offline-verifiable receipts with hash chaining, JCS compliance, SLSA provenance, and CLI verifier. 65 tests. Closes #1499.
847d741
into
microsoft:main
…#1519) * feat: offline-verifiable decision receipts (Ed25519 + JCS) - Add parent_receipt_hash for per-tool-call hash chaining - Enforce RFC 8785 JCS canonical JSON (ensure_ascii=False) - Add verify_receipt_chain() for offline chain verification - Add to_slsa_provenance() for SLSA v1.0 predicate emission - Add CLI verifier (scripts/verify_receipts.py) - Add tutorial (docs/tutorials/33-offline-verifiable-receipts.md) - 65 tests passing Closes microsoft#1499 * fix: address CodeQL and reviewer critical findings - Fix CodeQL high: use urlparse hostname check instead of substring match for builder URL validation (Incomplete URL substring sanitization) - Fix critical: verify_receipt_chain now flags unsigned receipts instead of silently skipping them, preventing unsigned receipt injection - Update tests to verify the unsigned receipt detection behavior * fix: address code-reviewer critical findings - Add session_id to GovernanceReceipt to prevent replay attacks by binding receipts to a specific execution context (Critical microsoft#1) - Add trusted_keys parameter to verify_receipt_chain for signer public key validation against a trusted set (Critical microsoft#3) - Add Unicode edge case tests: emoji, CJK, empty strings (Critical microsoft#4) - Add --json output flag to verify_receipts.py for CI/CD integration - 74 tests passing (9 new tests added) * fix: address second-round reviewer findings - CLI verify_receipts.py: structured per-receipt JSON output with exit codes (0=ok, 1=chain error, 2=load error) and --json flag detail - Tests: add Unicode edge cases (replacement char U+FFFD, Arabic RTL), SLSA schema field validation, inserted-receipt detection, and all-defaults unsigned receipt coverage (83 tests total) * refactor: simplify and clean up receipt, adapter, tests, and CLI - receipt.py: remove verbose docstrings; flatten to_slsa_provenance dict; tighten sign_receipt, verify_receipt, and verify_receipt_chain - adapter.py: collapse CedarPolicyEvaluator init; remove redundant comments; shorten govern_tool_call and govern_and_execute - verify_receipts.py: collapse _reconstruct and verify_chain; tighten main() - test_receipt.py: shared _make_chain helper; collapse unicode cases into one parametrized test; merge duplicate fixtures; 583 → 280 lines, same coverage * fix: address latest reviewer critical findings - verify_receipt: raise ImportError instead of silently returning False when cryptography library is missing - ReceiptSigningError: custom exception replaces generic RuntimeError in govern_tool_call for clearer failure context - ReceiptStore.add: enforce receipt_id uniqueness to prevent replay injection - verify_receipt_chain: validate signer_public_key is 64-char hex before trusted-key comparison to block malformed key bypass --------- Co-authored-by: Prashan Sapkota <prashansapkota@users.noreply.github.com>
The test-integrations matrix enumerates agentmesh-integrations packages explicitly. It was introduced in microsoft#226 (14 Mar 2026); mcp-receipt-governed was added six weeks later in microsoft#1510 and microsoft#1519 (27 Apr 2026) and was never enrolled, so no job has ever run its test suite. The module is not invisible to CI: the wheel-coherence job clean-venv imports mcp_receipt_governed from the agent-governance-toolkit-protocols umbrella wheel ("protocols import OK"). That import passes, which is part of why the missing test coverage was easy to miss. Signed-off-by: Arian Gogani <goganiarian@gmail.com>
Summary
Implements offline-verifiable decision receipts for the existing
mcp-receipt-governedadapter.Changes
mcp_receipt_governed/receipt.pyparent_receipt_hashfor hash chaining, RFC 8785 JCS compliance,to_slsa_provenance(), andverify_receipt_chain()mcp_receipt_governed/adapter.pyparent_receipt_hashfrom the last stored receiptmcp_receipt_governed/__init__.pyverify_receipt_chaintests/test_receipt.pyscripts/verify_receipts.pydocs/tutorials/33-offline-verifiable-receipts.mdStandards
Testing
blackformatting compliantCloses #1499