Skip to content

Commit fc88ea9

Browse files
committed
JCS conformance: canonical_hash_hex now uses strict RFC 8785 (mirrors SDK 2.6.0-alpha.4)
The Python SDK's compute_attribution_action_ref() hashes via canonical_hash_hex, which was using the legacy null-stripping canonicalize() instead of strict RFC 8785 canonicalize_jcs(). This is the Python mirror of today's TypeScript SDK fix (commit 3f63268 on agent-passport-system). Per draft-pidlisnyi-aps-01 §4.1 and ATTRIBUTION-PRIMITIVE-v1.1 §1.6, action_ref must follow strict RFC 8785 JCS. Cross-verified against erdtman/canonicalize@3.0.0 and rfc8785@0.1.4 in the TypeScript SDK; Python uses the in-process canonicalize_jcs() implementation which is byte-identical to those references. Tests: 518 passed, 1 skipped, 6 xfailed. Zero fixture changes required (no production pre-image ever contained a null-valued key at the canonicalization layer). Cross-language attribution settlement fixtures all byte-match unchanged. Known gap, scheduled for v3.0: hash_axis_leaf (Merkle) and envelope_bytes (signing envelope) still use legacy canonicalize() to preserve partner byte-match fixtures. v3.0 migration will coordinate fixture rotation across partners. Version: 2.4.0a2 -> 2.4.0a3
1 parent 38f176c commit fc88ea9

2 files changed

Lines changed: 14 additions & 3 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "agent-passport-system"
7-
version = "2.4.0a2"
7+
version = "2.4.0a3"
88
description = "Python SDK for the Agent Passport System. Identity, delegation, governance, data source registration, training attribution, per-period attribution settlement, mutual authentication, evidentiary type safety, Wave 1 accountability primitives (action, authority-boundary, custody, contestability, bundle), Cognitive Attestation, Instruction Provenance Receipts. Cross-language parity with agent-passport-system npm v2.6.0-alpha.3 verified by byte-identical canonical JSON fixtures."
99
readme = "README.md"
1010
license = "Apache-2.0"

src/agent_passport/v2/attribution_primitive/canonical.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from datetime import datetime, timezone
1010
from typing import Any, List, Union
1111

12-
from ...canonical import canonicalize
12+
from ...canonical import canonicalize, canonicalize_jcs
1313
from .types import (
1414
AttributionAxes,
1515
ComputeAxisEntry,
@@ -133,7 +133,18 @@ def hash_node(left: bytes, right: bytes) -> bytes:
133133

134134

135135
def canonical_hash_hex(obj: Any) -> str:
136-
return hashlib.sha256(canonicalize(obj).encode("utf-8")).hexdigest()
136+
"""SHA-256 hex over strict RFC 8785 JCS canonicalization.
137+
138+
Used for action_ref computation per draft-pidlisnyi-aps-01 §4.1 and
139+
ATTRIBUTION-PRIMITIVE-v1.1 §1.6. Cross-verified against the TypeScript
140+
SDK's canonicalHashJCS, erdtman/canonicalize@3.0.0, and rfc8785@0.1.4.
141+
142+
For Merkle leaf hashing (hash_axis_leaf) and signing envelope serialization
143+
(envelope_bytes), the legacy canonicalize() is still in use — those paths
144+
are scheduled for coordinated rotation in v3.0 because flipping them
145+
changes bytes across the existing partner fixture corpus.
146+
"""
147+
return hashlib.sha256(canonicalize_jcs(obj).encode("utf-8")).hexdigest()
137148

138149

139150
def envelope_bytes(env) -> str:

0 commit comments

Comments
 (0)