Skip to main content

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

Project description

pipelock-verify

PyPI Python CI CodeQL OpenSSF Scorecard 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.

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 · Usage · What gets verified · Canonicalization · Spec · Go reference

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

Maintainers: see RELEASING.md for the OIDC-based publish flow.

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.1.tar.gz (22.5 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.1-py3-none-any.whl (15.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pipelock_verify-0.1.1.tar.gz
  • Upload date:
  • Size: 22.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for pipelock_verify-0.1.1.tar.gz
Algorithm Hash digest
SHA256 1744a35c281ba065a9b8fb9132c0794226c99d22d224c97372da0896cc880ab1
MD5 0e7a8ab32b60251c9c45541631af7b7b
BLAKE2b-256 8d089e54c7bdfd0a67db29286f08bcdaea976d96ae3db03f9b8026a2b8be46a4

See more details on using hashes here.

Provenance

The following attestation bundles were made for pipelock_verify-0.1.1.tar.gz:

Publisher: release.yml on luckyPipewrench/pipelock-verify-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for pipelock_verify-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 317a44894615ff6ccbda356e0b0170c16f93dba826ed75021bd65c7252c04d9f
MD5 67d17a6e0e51aa6747e072c8803c50cd
BLAKE2b-256 b355cde7a087918b956c7aaf88cfe6752049da9cd86e2af9ce6a0d386dddbd80

See more details on using hashes here.

Provenance

The following attestation bundles were made for pipelock_verify-0.1.1-py3-none-any.whl:

Publisher: release.yml on luckyPipewrench/pipelock-verify-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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