Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.4.1] - 2026-10-12

### Fixed

- **Receipts from Pipelock parallel receipt chains now verify.** `verify()` and
`verify_chain()` accept the optional `group_binding` object that Pipelock signs
into `session_open` when `flight_recorder.receipt_chains` is greater than 1.
Before this release every shard of a grouped run failed with an unknown signed
field error. The binding is part of the signed projection in Go field order.
This is per-receipt and per-chain compatibility only: whole-group verification
(signed open and close manifests, shard membership, missing shards, the link to
a previous group and recovery tails) still needs Pipelock's own group verifier.
Receipts from single-chain runs verify as before.

### Documentation

- **The README states what a valid result does not prove.** It no longer says exit codes match `pipelock verify-receipt` or that the package mirrors the Go verifier without qualification. A valid chain is not proof that its end is present, a valid shard is not proof that a parallel-chain group is complete, and entries other than ActionReceipt v1 in a recorder file are not checked.

## [0.4.0] - 2026-07-30

### Added
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

**Python verifier for [Pipelock](https://github.com/luckyPipewrench/pipelock) receipts.** Supports **ActionReceipt v1** chains and individual **EvidenceReceipt v2** envelopes for contract-aware lifecycle events. Verifies Ed25519 signatures, v1 chain linkage, v2 payload schemas, key-purpose authority, and flight-recorder wrapping.

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.
Mirrors the Go reference implementation's signature, chain-linking and canonical-form checks byte-for-byte. The conformance golden files in `tests/conformance/` are generated by Pipelock's Go code and verified identically by both sides. It does not implement the end-of-chain proof or the whole-group verification that newer Pipelock releases add; see the section "What a valid result does and does not prove" below.

[Install](#install) · [Usage](#usage) · [EvidenceReceipt v2](#evidencereceipt-v2) · [Well-known directory](#well-known-directory) · [What gets verified](#what-gets-verified) · [Spec](https://pipelab.org/learn/action-receipt-spec/) · [Go reference](https://github.com/luckyPipewrench/pipelock)

Expand Down Expand Up @@ -116,7 +116,13 @@ python -m pipelock_verify evidence.jsonl \
--rotation-endorsement receipt-rotation-2026-07-30.json
```

Exit codes match `pipelock verify-receipt`: 0 on success, 1 on failure.
Exit codes: 0 on success, 1 on failure. In Pipelock releases that add end-of-chain proofs, `pipelock verify-receipt` also exits 3 for a valid chain whose end is not proven. This package has no such state.

### What a valid result does and does not prove

`CHAIN VALID` means every ActionReceipt v1 extracted from the file has a valid signature, the signer matches, and each receipt links to the one before it. Other entries in a flight-recorder file are not checked here: altering the signature on a wrapped EvidenceReceipt v2 entry still returns `CHAIN VALID`, while Pipelock's own `pipelock verify-receipt` rejects the recorder. It also does not prove the chain ends where it should. A chain cut off after a receipt still verifies, because this package has no end-of-chain proof. The exception is a chain verified with a rotation endorsement: cutting it before the rotation boundary leaves the endorsement unused, and that is rejected. In Pipelock releases that add end-of-chain proofs, `pipelock verify-receipt` reports a chain with no proven end as `VALID PREFIX, END UNPROVEN`. Use it when a missing tail matters.

Parallel receipt chains (`flight_recorder.receipt_chains` greater than 1) write one chain per shard. Each shard verifies on its own with this package, but a valid shard does not show that the group is complete. Shard membership, missing shards, the signed group open and close, and the link to a previous group still need Pipelock's own group verifier.

## EvidenceReceipt v2

Expand Down
2 changes: 1 addition & 1 deletion pipelock_verify/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
verify_chain,
)

__version__ = "0.4.0"
__version__ = "0.4.1"

__all__ = [
"PAYLOAD_AUTHORITY",
Expand Down
5 changes: 3 additions & 2 deletions pipelock_verify/__main__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Command-line interface for ``python -m pipelock_verify``.

Verifies a single receipt JSON file or a flight recorder JSONL chain.
Exit code 0 on success, 1 on failure — same convention as the Go
``pipelock verify-receipt`` command.
Exit code 0 on success, 1 on failure. Pipelock releases that add end-of-chain
proofs also exit 3 from ``pipelock verify-receipt`` for a valid chain whose end
is not proven; this CLI has no such state.
"""

from __future__ import annotations
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "pipelock-verify"
version = "0.4.0"
version = "0.4.1"
description = "Verify Pipelock receipts: ActionReceipt v1 chains and individual EvidenceReceipt v2 envelopes."
readme = "README.md"
license = "Apache-2.0"
Expand Down
Loading