Offline Kit Import Verification Runbook

Status: script paths re-checked against commit 942a18727c (2026-09-26); the script behaviour and exit codes were not re-verified.

This runbook supports AIRGAP-MANIFEST-510-010, AIRGAP-REPLAY-510-013, and AIRGAP-VERIFY-510-014. It validates bundles fully offline and enforces replay depth.

Replay depth levels (manifest replayPolicy)

Quick steps

src/OfflineKit/scripts/verify-kit.sh \
  --manifest offline-kit/manifest.json \
  --bundle offline-kit/bundle.tar.gz \
  --signature offline-kit/manifest.sig --pubkey offline-kit/manifest.pub.pem \
  --av-report offline-kit/reports/av-report.json \
  --receipt offline-kit/receipts/ingress.json \
  --sealed-policy-hash "aa55..." \
  --depth policy-freeze

What the script enforces

  1. Manifest & bundle digests match (hashes.*).
  2. Optional manifest signature is valid (OpenSSL).
  3. Staleness: createdAt must be within stalenessWindowHours of --now (defaults to UTC now).
  4. AV: avScan.status must not be findings; if reportSha256 is present, the provided report hash must match.
  5. Chunks (full-recompute/policy-freeze): every chunks[].path exists relative to the manifest and matches its recorded SHA-256.
  6. Policy-freeze: --sealed-policy-hash must appear in policies[].sha256.
  7. Optional: --expected-graph-sha checks the graph chunk hash; --receipt reuses verify-receipt.sh to bind the receipt to the manifest/bundle hashes.

Exit codes: hash mismatch (3/4), staleness (5), AV issues (6–8), chunk drift (9–10), graph mismatch (11), policy drift (12–13), bad depth (14).

Server-side import

This runbook verifies a kit on the client side. It does not admit anything into an estate. The server-side import of a signed carrier is POST /api/offlinekit/v1/import on offlinekit-web (stella airgap import); see ../guides/importer.md. The predecessor controller endpoint POST /system/airgap/verify that applied these replay rules server-side was withdrawn with the airgap-controller host.

References