build(agent): weasel-1#856f80 iteration

This commit is contained in:
agent-856f80a92b1141b4 2026-04-24 20:20:04 +02:00
parent b71a0d1e4b
commit 04ed82bc21
2 changed files with 32 additions and 0 deletions

View File

@ -3,6 +3,8 @@ from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Any
import time
import json
import hashlib
@dataclass
@ -58,5 +60,30 @@ class GraphOfContractsRegistry:
raise KeyError(f"Contract {contract_id} not found")
rec.attestations.append(attestation)
def generate_attestation(self, contract_id: str) -> str:
"""Create a deterministic SHA-256 attestation for a registered contract.
The attestation is computed over a canonical JSON serialization of the
contract metadata (name, version, contract_id, schema, signer, timestamp)
to ensure repeatability for audits and replay checks.
"""
rec = self.contracts.get(contract_id)
if rec is None:
raise KeyError(f"Contract {contract_id} not found")
# Canonical JSON serialization for deterministic hashing
payload = {
"name": rec.name,
"version": rec.version,
"contract_id": rec.contract_id,
"schema": rec.schema,
"signer": rec.signer,
"timestamp": rec.timestamp,
}
data = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
h = hashlib.sha256(data).hexdigest()
att = f"sha256:{h}"
rec.attestations.append(att)
return att
__all__ = ["ContractRecord", "GraphOfContractsRegistry"]

View File

@ -18,3 +18,8 @@ def test_registry_basic_operations():
assert c.name == "toyAdapter"
reg.add_attestation("idea-1", "attestation-123")
assert reg.get_contract("idea-1").attestations[-1] == "attestation-123"
# generate deterministic sha256 attestation and ensure it's appended
att = reg.generate_attestation("idea-1")
assert isinstance(att, str)
assert att.startswith("sha256:")
assert reg.get_contract("idea-1").attestations[-1] == att