Skip to main content

norcaster-verify

Independent verification tooling for Norcaster evidence. It verifies without a Norcaster account, without API access and without trusting Norcaster. Everything below runs offline.

Two uses:

  1. Verify an audit bundle: the evidence package Norcaster exports for SOC 2 examinations and EU AI Act readiness reviews (Python, norcaster-verify on PyPI).
  2. Verify a Shared Record exchange or dispute export: what two companies' agents exchanged, signed by both and logged as hashes (Python or Node; the protocol is a draft, see below).

The examples run from a clone of this repository, against files committed in it:

git clone https://github.com/norcaster/verify.git && cd verify

1. Verify an audit bundle

pip install norcaster-verify
norcaster-verify examples/audit-bundle.json --offline

examples/audit-bundle.json is a small synthetic bundle. Expected result: PASS, with the content digest, governing configuration and approval provenance checks passing, and the trace chain snapshot and public Rekor anchors reported as SKIP because the example carries none. A SKIP is never a PASS.

Change one recorded decision and verify again:

python -c "import json; b = json.load(open('examples/audit-bundle.json')); b['sections']['enforcement_records'][2]['outcome'] = 'allowed'; json.dump(b, open('tampered-bundle.json', 'w'))"
norcaster-verify tampered-bundle.json --offline

Expected result: FAIL on the bundle content digest, exit code 1.

For a real bundle, run norcaster-verify bundle.json (online, it looks up the Rekor anchors), --offline (it uses the Rekor snapshots embedded in the bundle) or --json (a machine-readable report). Exit code 0 means no check failed.

What it checks:

  • the manifest's content digest;
  • the internal integrity references;
  • the public Sigstore Rekor anchors;
  • governing-configuration consistency: every enforcement decision's deployment_policy_version / policy_content_hash resolves to a policy snapshot in the bundle whose hash recomputes. Org-scoped decisions, which have no deployment, resolve their org_policy_version against org_policy_version_snapshots;
  • approval provenance: policy versions produced by a config proposal name an independent approver and appear in change_history.

For anchors written by a signing-enabled chain it also checks that the Rekor entry embeds the tenant's public key named in the manifest and a valid ES256 signature over the segment root. That needs pip install "norcaster-verify[signatures]"; without cryptography that part reports SKIP, not PASS.

The same two files (verify_audit_bundle.py, audit_bundle_verify_lib.py) ship inside every Norcaster audit-bundle zip. This package and the bundled copies are interchangeable, and a test enforces that they are identical byte for byte.

2. Verify a Shared Record exchange or dispute export

A Shared Record export is one JSON evidence file: the signed receipts, acknowledgements and missing-acknowledgement records for the exchanges in question, their log proofs, a witnessed checkpoint, both organisations' key documents and, for exchanges a party chose to reveal, the content and salt. You verify it against your own trust file: the root fingerprints you pinned for each organisation and the log and witness keys you trust.

Each test vector in spec/vectors/ holds both, plus the expected result. Split one into the two files the verifier takes:

python -c "import json; v = json.load(open('spec/vectors/valid-acknowledgement.json')); json.dump(v['evidence'], open('evidence.json', 'w')); json.dump(v['trust'], open('trust.json', 'w'))"

Python:

pip install "norcaster-verify[signatures]"
python -m norcaster_verify.shared_record verify evidence.json --trust trust.json

Node (18 or later), the same checks:

npx --yes --package @norcaster/verify norcaster-verify-record evidence.json --trust trust.json

Expected result: the exchange state=acknowledged, Result: no check failed and exit code 0. Every check passes except two that do not apply here and say so as SKIP: there is no missing-acknowledgement record, and the evidence holds one checkpoint, so there is no earlier one to prove consistency with. The receipt's content commitment is checked against the revealed content and salt (content_commitment: revealed content and salt match the commitment).

Now a copy whose receipt was changed after it was signed:

python -c "import json; v = json.load(open('spec/vectors/tampered-content-hash.json')); json.dump(v['evidence'], open('evidence.json', 'w')); json.dump(v['trust'], open('trust.json', 'w'))"
python -m norcaster_verify.shared_record verify evidence.json --trust trust.json

Expected result: FAIL on the receipt signature, the content commitment and the receipt's log inclusion, and exit code 1. Add --json to either command for a machine-readable report. Without the signatures extra the Python verifier reports signature checks as SKIP, never PASS; Node always checks them. Python and Node give the same report, byte for byte, on every input.

Profiles. The default, --profile basic, reports what the evidence shows. For a dispute, add --profile dispute: every log check (receipts, acknowledgements, missing-acknowledgement records, key-document versions and root rotations) must then PASS, and a SKIP counts as a FAIL. Either way the report says, per organisation (evidence_complete_for), that the result assumes the export holds the organisation's complete key history, which v0 evidence cannot show:

python -m norcaster_verify.shared_record verify evidence.json --trust trust.json --profile dispute

Input. Both verifiers read the evidence and trust files as text under a strict JSON profile (spec §4.1): no number with a fraction or an exponent, no NaN, no duplicate member names. A file outside it is unusable input: the report's input section says why, and the exit code is 2. From code, use verify_evidence_text(evidence_text, trust_text, profile="basic") in Python or verifyEvidenceText(evidenceText, trustText, { profile }) in Node; verify_evidence and verifyEvidence take parsed JSON, which can no longer show those mistakes.

The 25 vectors and what each must give are listed in spec/vectors/, and 52 negative vectors (malformed input, as text) in spec/vectors/negative/. An export from a Norcaster organisation (POST /orgs/{org}/shared-record/dispute-exports) or from the self-hosted counterparty component (norcaster-counterparty export) verifies the same way.

Shared Record status

In development · pilot pairs by application. A pilot version is built and in testing. It is not in production or available to customers.

spec/shared-record-v0.md is a draft protocol, in development, published for review. It is designed on the IETF SCITT architecture (RFC 9943), using COSE hash envelopes (RFC 9995), COSE Receipts (RFC 9942) and the RFC 9162 Merkle tree. It may change. The Python module norcaster_verify.shared_record is its reference implementation and lib/shared-record/ its Node verifier. spec/REVIEW.md is the brief for an outside review of the protocol. The record shows what each party signed and what the log recorded; it does not decide who is right.

3. Verify a trace integrity proof (Node)

Verifies a per-run trace integrity proof bundle (norcaster-proof-<run_id>.json): the local hash-chain proof, the Merkle path, and one Rekor lookup to confirm the segment root against the public transparency log. This one is online.

npx --yes --package @norcaster/verify norcaster-verify-proof --proof norcaster-proof-<run_id>.json

What it checks: the recorded chain-proof result carried in the bundle, the Merkle inclusion path when one is present, the tenant-key (ES256) signature over the entry and, where the Merkle path allows, over the segment root, and that the segment root and public key in the Rekor entry match what the bundle carries. It does not recompute the full hash chain, and the Rekor URL comes from the bundle itself. See docs/algorithm.md for exactly what each step proves. Unsigned (version 1) bundles are reported as unsigned, never as verified. The npm package installs two commands, norcaster-verify-proof and norcaster-verify-record, distinct from the Python norcaster-verify command.

What verification does not prove

Completeness of an AI estate, compliance with any framework, or authenticity of the export source. Norcaster produces evidence; only a licensed CPA firm can attest under SOC 2, and EU AI Act conformity determinations require qualified counsel. A Shared Record verification shows what was signed and logged, not which party is right about a dispute.

Source and releases

This repository is a published snapshot of packages/norcaster-verify in Norcaster's main repository, which is the source of truth. The Python files here are byte-for-byte the ones that ship inside every audit-bundle zip, and a test in the main repository enforces that. Open issues here.

Releases are cut from version tags (v0.4.0). The release.yml workflow builds the Python sdist and wheel and publishes them to PyPI, and publishes the npm package, using each registry's trusted-publishing (OIDC) flow, with no long-lived tokens. The versions in pyproject.toml and package.json and the top entry of CHANGELOG.md must all equal the tag. CI runs the Node and Python tests on every push.

Security reports: see SECURITY.md.

Apache-2.0 · security@norcaster.com

Metadata

Release files for norcaster-verify 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for norcaster-verify 0.4.0
File Size Uploaded Provenance Actions
norcaster_verify-0.4.0.tar.gz 292.7 kB With provenance Details for norcaster_verify-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for norcaster-verify 0.4.0
File Interpreter ABI Platform Actions
norcaster_verify-0.4.0-py3-none-any.whl Python 3 none any Details for norcaster_verify-0.4.0-py3-none-any.whl

Total release size: 344.6 kB

Release files / norcaster_verify-0.4.0.tar.gz

Download URL norcaster_verify-0.4.0.tar.gz
Size 292.7 kB
Tags Source
SHA-256 checksum
How to use checksums
698124b0a6dc1654aa96b4a3d70709b5a25ca0108c7b3e69fdc3faa75aeb5d85
BLAKE2b-256 checksum
How to use checksums
b8cf5ef3397ae3ba4ad723ee61cc02ec3dc58038c866c348eb90c000e610639a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Release files / norcaster_verify-0.4.0-py3-none-any.whl

Download URL norcaster_verify-0.4.0-py3-none-any.whl
Size 51.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d1481d0b9375d0dc828dc97053b0ec096988a31fc10a6492943c7cd201140b67
BLAKE2b-256 checksum
How to use checksums
17bca37ce24d42588e9ab5d7c7452f0640bef46f80339cb19acf5c02e7813ffd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Security for norcaster-verify 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for norcaster_verify-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page