Exporting a locker

Getting a portable, verifiable copy of a run's evidence.

An export packages one sealed run as a zip that can be checked without Pentr. There is no console screen for it — the Evidence sidebar entry is greyed out — so the export is an HTTP call.

The call

API="https://<your-console-host>"  # same origin as the console; there is no separate API host
TOKEN=...                         # your Kratos session token
ENGAGEMENT_ID=...                 # the engagement to export

curl -OJ -H "Authorization: Bearer $TOKEN" \
  "$API/api/engagements/$ENGAGEMENT_ID/locker"

The response is application/zip, named pentr-locker-<engagement id>.zip. The zip is built on demand for each request, so two exports of the same run are not byte-identical: seal.json records a fresh exported_at, and each member is stamped with the time it was written into the archive. Nothing that the signature covers changes between them.

Failure responses:

Status Meaning
404 No such engagement, or it belongs to another organization. The two answer identically on purpose.
409 The run is not sealed, so there is nothing to export.
409 The run was sealed before signing existed and has no signature. It cannot be exported as a verifiable locker.
500 The server cannot read the evidence store, or the signing key row the seal names is gone.

To hand a locker to someone without an account, use a share link instead; it serves the same zip.

What is in the zip

manifest.json
signature_block.json
signature.bin
public_key.pem
seal.json
README.txt
artifacts/<sha256>

manifest.json — the sealed, ordered record of every artifact: the format version, the chain algorithm, the genesis value, the run block with the framework and scope digest, one object per entry, the chain head and the entry count. The bytes are copied from the store exactly as they were hashed.

signature_block.json — the bytes that were signed. It holds the signature version and algorithm, the chain head, the manifest's SHA-256, the signing key id and signed_at.

signature.bin — the raw Ed25519 signature over those bytes.

public_key.pem — the public half of the key named by the seal. A recipient who wants to prove provenance pins a copy they obtained from you independently and passes it with --key; the bundled copy alone proves only internal consistency.

seal.json — an unsigned summary header: the locker format, the run id, the chain head, the manifest hash, the entry count, the algorithms, the signing key id, signed_at, sealed_at and exported_at. Nine of the eleven are cross-checked at verification time: eight against the signed bytes, and the format against the verifier's own version constant. sealed_at and exported_at are checked against nothing, so neither is evidence of when the run was sealed or when the archive was produced.

README.txt — how to verify the locker, what a pass and a fail mean, and a note on key custody. It is not covered by the signature.

artifacts/<sha256> — one file per sealed artifact, named by its hash, flat under artifacts/ with no further directories. Every entry in the manifest has a file here, and a file under artifacts/ that no entry names is a verification failure rather than a harmless extra. A member with any other top-level name, or a path that walks outside the locker, is rejected before verification begins: a malformed locker rather than a tampered one.

Three version strings

The locker's packaging version, the manifest's schema version and the signature block's version are separate values that all read pentr-locker-1. They are deliberately not aliases of one another: the container format, the manifest schema and the signature block schema are three concerns that happened to ship together, and each has to be able to change without the others. If the manifest schema were bumped through a shared constant, the locker would silently start advertising a container format that had not changed.

Read seal.json's format for the container, manifest.json's version for the manifest, and signature_block.json's version for the block.

Next

Verifying a locker is what the recipient does with the zip: installing pentr-verify, running it against the file, and reading the result.

Last updated 2026-09-24