Pramiti Docs
Praxom

Attestation Store

Ed25519 signing, append-only storage, and tamper-evident audit trail

The Attestation Store records every policy decision as an immutable, cryptographically signed record. This provides a regulator-grade audit trail suitable for EU AI Act compliance, SOC 2 requirements, and internal governance.

How It Works

Signing (contexts/praxom/attestation/domain/signing.py)

Every attestation is signed with Ed25519 (v5+) for tamper evidence:

from pramiti.contexts.praxom.attestation.domain.signing import compute_ed25519_signature

signature = compute_ed25519_signature(
    private_key_b64=signing_key,
    verdict="allow",
    tool_name="salesforce.update_contact",
    agent_id="agent-7",
    payload_hash=hash_payload(arguments),
    impact_hash=hash_impact_set(impact_set),
    timestamp=timestamp
)

The signing message includes all material fields: verdict, tool name, agent ID, payload hash, impact hash, constraint IDs, delegation fields, and evidence classification. This ensures any modification to any field invalidates the signature.

Signature versions:

  • v1-v4, v6, v8 — HMAC-SHA256 (symmetric; v8 also has an Ed25519 form)
  • v5, v7, v8, v9 — Ed25519 (asymmetric)
  • v9 — current; HMAC and Ed25519. The store writes version 9 (decision_source is in the signed message).

Ed25519 key generation:

from pramiti.contexts.praxom.attestation.domain.signing import generate_ed25519_keypair

private_key_b64, public_key_b64 = generate_ed25519_keypair()

PraxomAttestationStore

The PraxomAttestationStore class manages attestation lifecycle:

  • record() — Creates a new attestation record with signature
  • verify() — Validates the signature of an existing record
  • query() — Retrieves attestations by workspace, agent, tool, time range, or verdict

Append-Only Storage

Attestation records are stored in the praxom_attestations PostgreSQL table which is protected by a database trigger that prevents UPDATE and DELETE operations. Only INSERT is allowed. This is enforced at the database level, not the application level, making it tamper-resistant even if the application is compromised.

Export (contexts/praxom/attestation/domain/export.py)

Attestations can be exported in multiple formats:

  • JSON — Full structured export with all fields
  • CSV — Tabular export for spreadsheet analysis
  • JSON-LD — Linked data format for regulatory submissions

Exports support filtering by workspace, time range, verdict, agent, and tool pattern (via fnmatch glob matching).

Crypto (crypto.py)

Fernet encryption for downstream connection credentials:

  • encrypt_config() — Encrypts connection configuration with a derived key
  • decrypt_config() — Decrypts configuration
  • redact_config() — Returns configuration with sensitive values masked (for display)

Architecture

Policy Decision
    ↓
AttestationStore.record()
    ├── compute_ed25519_signature()
    ├── hash_payload() — SHA-256 of action arguments
    ├── hash_impact_set() — SHA-256 of blast radius
    └── INSERT INTO praxom_attestations (append-only)
    ↓
SIEM Enqueue (parallel, best-effort)

Configuration

# Ed25519 signing key (required for production)
EPISTOM_PRAXOM_ED25519_PRIVATE_KEY=<base64-encoded-ed25519-private-key>

# HMAC dev signing key (dev/demo posture only — distinct from the Ed25519 key)
EPISTOM_PRAXOM_SIGNING_KEY=<hmac-key>

# Fernet encryption key (required for credential storage)
EPISTOM_ENCRYPTION_KEY=<fernet-key>

Generate keys:

# Ed25519 signing key
python3 -c "from pramiti.contexts.praxom.attestation.domain.signing import generate_ed25519_keypair; priv, pub = generate_ed25519_keypair(); print(f'Private: {priv}\nPublic: {pub}')"

# Fernet key
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

Technical Details

  • The _reconstruct_ed25519_message() function rebuilds the signing message from a stored attestation for verification
  • Payload hashing uses SHA-256 (hash_payload()) with deterministic JSON serialization
  • The summarize_payload() function creates a truncated human-readable summary (max 500 chars) stored alongside the hash
  • Database triggers refuse UPDATE/DELETE for ordinary roles. A table owner or superuser can DISABLE TRIGGER, and DELETE is permitted when epistom.audit_delete_override=true (authorized retention sweep).
  • The audit_logs table uses the same append-only pattern with HMAC tamper detection

On this page