Verify your cost-audit chain externally
Vupt publishes a public bash verifier — scripts/verify-cost-chain.sh — that runs on your machine, offline, against any NDJSON export bundle. The per-organization Ed25519 public key is embedded on every row, so no network call to Vupt is required. This page is the auditor guide.
Why verify externally
Trust without verification is unsuitable for regulated workloads. Following the Kyriba 2026 Operational Resilience Index's verify, then trust framework, Vupt ships the cryptographic primitives, the public verification keys, and an auditor-runnable script — together with the audit data itself. ADR-011 commits Vupt to per-org Ed25519 audit chains; this page closes the loop by giving you the tool to audit them independently.
Prerequisites
The verifier is a single bash script with portable dependencies. No Node runtime, no language SDK, no package manager. Installation is whatever your distribution already ships. OpenSSL 3.0+ is required because Ed25519 verification via pkeyutl needs the -rawin flag added in OpenSSL 3.0; the older 1.1.1 ships Ed25519 keys but cannot verify them via the pkeyutl command.
bash4.0+jq1.5+openssl3.0+ (required for Ed25519 verification via pkeyutl -rawin)sha256sum+base64(GNU coreutils or BSD)
Quick start
bash scripts/verify-cost-chain.sh <ndjson-file>For continuous-integration pipelines, --json emits a structured, locale-neutral payload you can pipe through jq.
bash scripts/verify-cost-chain.sh --json <ndjson-file>The verifier dispatches human-readable output on the LANG env var. Set pt_BR.UTF-8 for Brazilian Portuguese.
LANG=pt_BR.UTF-8 bash scripts/verify-cost-chain.sh <ndjson-file>Output examples
Success
OK: chain verified — 1432 rows — signature OK — chain-tip a4b2c8d1Chain broken (exit 1)
VERIFICATION FAILED: row 1342 prev_hash mismatch (expected abc123..., got def456...)Signature invalid (exit 2)
VERIFICATION FAILED: row 27 signature invalid (Ed25519 verify failed)Malformed input (exit 3)
VERIFICATION FAILED: malformed NDJSON at line 813 (JSON parse failed)Exit codes
- 0 — Chain verified — every signature valid + every prev_hash matches.
- 1 — Chain broken — at least one row's prev_hash did not match the SHA-256 of the previous row.
- 2 — Signature invalid — at least one row's Ed25519 signature did not verify against the embedded public key.
- 3 — Malformed input — NDJSON parse error, missing required field, missing input file, or missing tooling.
JSON output (--json)
The --json flag emits a single-line JSON object suitable for CI pipelines. The shape is fixed; status is either ok or failed; reason is one of prev_hash_mismatch, signature_invalid, or malformed.
{"status":"ok","rows":1432,"chain_tip":"a4b2c8d1e9f7..."}{"status":"failed","reason":"prev_hash_mismatch","line":1342,"detail":"..."}NDJSON envelope schema
Each line in the export bundle is one JSON object. The full envelope contract — what Vupt's export worker writes and what the verifier consumes:
{
"id": "<ulid>",
"prev_hash": "<64-char hex SHA-256>",
"payload": { /* JCS-canonicalizable JSON */ },
"signature": "<base64 Ed25519 signature>",
"signing_key_pem": "<PEM SPKI Ed25519 public key>",
"key_id": "<rotation history identifier>",
"active_key_id": "<currently-active per-org key id>",
"created_at": 1716285600000,
"action": "cost.attribution_recorded",
"jcs_canonical_bytes_b64": "<base64 of RFC 8785 JCS bytes>"
}Air-gapped verification
Because every NDJSON row embeds the per-organization signing_key_pem, the verifier runs offline. No outbound network access is required. This is the same script you would use in an air-gapped audit room, on a regulator's sealed laptop, or inside a customer's own VPC. Vupt does not need to be reachable to validate your audit chain.
Source and further reading
The verifier is MIT-licensed and lives in the Vupt monorepo. All design decisions are public.
The verify-cost-chain.sh script ships bundled with the desktop installer for offline inspection — open it from your installation directory under scripts/. Source repository is private during the design-partner phase; public re-publication is planned alongside v1.4.