Skip to main content

Verify Pipelock action receipts (Ed25519-signed, chain-linked).

Project description

pipelock-verify

PyPI version Python versions CI License: Apache-2.0

Python verifier for Pipelock action receipts. Verifies the Ed25519 signature, chain linkage, and flight-recorder wrapping of receipts emitted by the Pipelock mediator.

The library mirrors the Go reference implementation byte-for-byte. The conformance golden files in tests/conformance/ are generated by Pipelock's Go code and verified identically by both sides.

Install

pip install pipelock-verify

Only one runtime dependency: cryptography for the Ed25519 primitives.

Usage

Single receipt

import pipelock_verify

with open("receipt.json", "rb") as f:
    result = pipelock_verify.verify(f.read())

if not result.valid:
    raise SystemExit(f"bad receipt: {result.error}")

print(f"OK: {result.action_id} {result.verdict} {result.target}")

Pin a specific signing key to reject receipts from any other signer:

PROD_KEY = "70b991eb77816fc4ef0ae6a54d8a4119ddc5a16c9711c332c39e743079f6c63e"
result = pipelock_verify.verify(receipt_bytes, public_key_hex=PROD_KEY)

Receipt chain

Pass a flight-recorder JSONL path:

chain = pipelock_verify.verify_chain("evidence-proxy-0.jsonl")

if not chain.valid:
    raise SystemExit(
        f"chain broken at seq {chain.broken_at_seq}: {chain.error}"
    )

print(f"CHAIN VALID: {chain.receipt_count} receipts, root {chain.root_hash}")

When no trust anchor is supplied, the first receipt's signer_key becomes the expected key for the rest of the chain. This matches the signer- consistency check in Go's receipt.VerifyChain.

CLI

python -m pipelock_verify receipt.json
python -m pipelock_verify evidence.jsonl
python -m pipelock_verify evidence.jsonl --key 70b991eb77816fc4...

Exit codes match pipelock verify-receipt: 0 on success, 1 on failure.

What gets verified

On a single receipt:

  • Envelope version (rejects anything other than v1).
  • Action record version (rejects anything other than v1).
  • Required action record fields (action_id, action_type, timestamp, target, verdict, transport).
  • Signature format (ed25519:<hex> prefix, 64-byte length).
  • Signer key format (32-byte hex).
  • Optional trust anchor match (public_key_hex argument).
  • Ed25519 signature over SHA-256(canonical action record).

On a chain:

  • Every individual receipt above.
  • Signer consistency (every receipt uses the same signer_key, or the pinned trust anchor if one was supplied).
  • Monotonic chain_seq starting at 0.
  • chain_prev_hash linkage: each receipt's chain_prev_hash equals SHA-256 of the previous receipt's canonical envelope, in hex.
  • First receipt's chain_prev_hash equals the literal string "genesis".

Failing receipts return the first break point (broken_at_seq) and a descriptive error, the same shape the Go CLI prints.

Input formats

verify_chain() accepts JSONL in two shapes:

  1. Flight-recorder entries — the format Pipelock actually writes to disk. Each line is a recorder.Entry object with type == "action_receipt" and the receipt nested in detail. Non-receipt entries (checkpoints etc.) are skipped, not rejected.
  2. Bare receipts — one receipt object per line, no wrapping. Used by the conformance suite and handy for ad-hoc testing.

verify() accepts:

  • A JSON string or UTF-8 bytes.
  • A pre-parsed dict (for callers that already have the receipt loaded).
  • A flight-recorder entry dict (transparently unwrapped).

Canonicalization rules

The signing input is the SHA-256 of the Go json.Marshal output of the ActionRecord struct. "Canonical" means matching that exactly:

  • Fields emitted in Go struct declaration order (not alphabetical).
  • omitempty fields dropped when the value is the Go zero value ("", empty slice, 0, false, nil).
  • Compact JSON (no whitespace between tokens).
  • HTML-safe escapes: <, >, &, U+2028, U+2029 encoded as Unicode escapes, matching Go's default encoding/json behavior.
  • Fields unknown to the v1 schema are dropped (matches Go json.Unmarshal round-trip behavior).

Any deviation produces different bytes, a different hash, and a failed signature. See pipelock_verify/_canonical.py for the full rule set.

Relationship to the Go reference

Both implementations verify the same sdk/conformance/testdata/ golden files and compute identical root hashes.

Development

git clone https://github.com/luckyPipewrench/pipelock-verify-python
cd pipelock-verify-python
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest

To refresh the conformance fixtures from a local Pipelock checkout:

cd /path/to/pipelock
go test ./sdk/conformance/ -run TestGenerateGoldenFiles -update
cp sdk/conformance/testdata/*.{json,jsonl} \
   /path/to/pipelock-verify-python/tests/conformance/
pytest

License

Apache 2.0. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pipelock_verify-0.1.0.tar.gz (21.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pipelock_verify-0.1.0-py3-none-any.whl (15.3 kB view details)

Uploaded Python 3

File details

Details for the file pipelock_verify-0.1.0.tar.gz.

File metadata

  • Download URL: pipelock_verify-0.1.0.tar.gz
  • Upload date:
  • Size: 21.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pipelock_verify-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8beea285ada9206f16030b781b61eebcc0c9348fba129e0f0eefd44817e965ff
MD5 20d18732672dfa3c0862b01312977c77
BLAKE2b-256 6fc3325405ae496e71f897524fec75c29001d8f0e5a8c568a8d2d99d6b17a34e

See more details on using hashes here.

File details

Details for the file pipelock_verify-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pipelock_verify-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fd8a357db500d60c6af375d472c74d30cf9736ecfdc9e312e822d68cdd553351
MD5 c32848eaf1e2ffd4f512d458419ff3ca
BLAKE2b-256 0e44335162806ebfe0140cfe7d6e03f296a7cd9e4d1a8763ce24a174a4e8c6c8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page