@nexart/cli 0.15.1 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,104 @@
1
1
  # @nexart/cli — Changelog
2
2
 
3
+ ## v0.16.1 (2026-06-17) — `verify-record`: 3-state verification (VERIFIED / AUTHENTIC (REDACTED) / FAILED)
4
+
5
+ UX release. `verify-bundle` is **byte-for-byte unchanged**; the new third state applies
6
+ to `verify-record` (and the `verify-url` / `verify-hash` commands that render through it).
7
+
8
+ - **Privacy-redacted records are no longer reported as FAILED.** A public record served
9
+ from a node may have the snapshot's `input` / `output` *content* stripped while the
10
+ `inputHash` / `outputHash` anchors are kept. Because `certificateHash` is sealed over the
11
+ full snapshot, recompute is impossible on a redacted snapshot — but that is **not
12
+ tampering**. Such records now report **`FINAL STATUS: AUTHENTIC (REDACTED)`** with
13
+ **`⚠ Integrity: NOT RECOMPUTABLE (redacted)`** and **exit 0**, provided the receipt
14
+ signature still verifies.
15
+ - **Three exit-stable states.** `VERIFIED` (exit 0) → content present, hash recomputes;
16
+ `AUTHENTIC (REDACTED)` (exit 0) → content stripped, hashes kept, signature passes;
17
+ `FAILED` (exit 1) → a real content mismatch or an invalid signature. A genuine mismatch
18
+ is **never** softened to redacted, and a redacted record whose hash still recomputes
19
+ stays **VERIFIED**.
20
+ - **Report.** For a redacted record the Signature line is shown before the Integrity line,
21
+ and a short **Public Verification (Redacted)** note explains that full integrity
22
+ verification requires the original (un-redacted) execution data. `--short` now emits
23
+ `✔ VERIFIED` / `⚠ AUTHENTIC (REDACTED)` / `✖ FAILED`. `--json` gains a `redacted`
24
+ boolean, an `authentic-redacted` `status`, and a `redacted` `integrity` value.
25
+ - **No cryptographic change.** `certificateHash` computation, canonicalisation, and the
26
+ signature / timestamp logic are untouched — this is purely a classification and
27
+ presentation layer. `verify-bundle` does not opt into redaction classification and is
28
+ byte-for-byte unchanged.
29
+ - **UX hardening.** The redacted context block now names the redaction source
30
+ (`Redaction: Applied by certification node (privacy mode)`) and sits tight under the
31
+ headline. A present-but-unverifiable timestamp (parse failure, or verification not
32
+ attempted) reports `⚠ Timestamp: PRESENT BUT NOT VERIFIED` instead of
33
+ `INVALID (malformed token)`, and a missing one reports `Timestamp: NOT INCLUDED` — the
34
+ timestamp still never affects `FINAL STATUS`. Section order is fixed: Signature →
35
+ Integrity → Timestamp → Node → Identity → Execution.
36
+ - **Timestamp compatibility (no longer "malformed token").** RFC 3161 timestamp
37
+ verification now accepts the full `TimeStampResp` returned by the certification node
38
+ (PKIStatusInfo + `timeStampToken`) in addition to a bare `TimeStampToken` (CMS
39
+ `ContentInfo`). The wrapper is detected structurally and unwrapped to the inner
40
+ `ContentInfo` before the unchanged signature / imprint / chain checks run. This is a
41
+ parsing-layer fix only — `certificateHash`, the imprint binding, the signature logic,
42
+ and the "timestamp never affects `FINAL STATUS`/exit code" invariant are all
43
+ unchanged; an unparseable token still degrades to `PRESENT BUT NOT VERIFIED`.
44
+
45
+ ## v0.16.0 (2026-06-17) — `verify-record`: fully automatic, audit-grade, self-contained
46
+
47
+ Feature release. `verify-bundle` is **byte-for-byte unchanged** — the redesigned
48
+ output and automatic key/timestamp resolution apply to `verify-record` only.
49
+
50
+ - **Automatic verification.** `nexart verify-record <file>` now verifies integrity,
51
+ the receipt signature, **and** the RFC 3161 timestamp with no extra flags. The
52
+ `--verify-timestamp` gate is gone — timestamp verification always runs when a token
53
+ is present (the ASN.1 stack still loads lazily, only when a token exists).
54
+ - **Self-contained signing key resolution.** By priority: `--public-key` (explicit
55
+ override) → auto-fetched from the node's published key set at
56
+ `https://node.nexart.io/.well-known/nexart-node.json` (the key whose `kid` matches
57
+ the receipt's `attestorKeyId`) → a bundle-embedded key. The fetch is the **only**
58
+ network call, lives entirely in the CLI layer (the auditable `standaloneVerify.ts`
59
+ core stays `node:crypto`-only / no network), and fails gracefully. New **`--offline`**
60
+ flag disables it; the URL is overridable via `NEXART_NODE_WELLKNOWN_URL`.
61
+ - **Embedded DigiCert trust store.** Timestamps verify against a built-in trust store
62
+ (DigiCert Trusted Root G4 + DigiCert Assured ID Root CA) by default; **`--tsa-roots`**
63
+ overrides it with custom PEM roots.
64
+ - **Flexible input.** The bundle is read from `record.bundle` or, failing that, the
65
+ record root is treated as the bundle. The old "missing bundle" error is removed — a
66
+ malformed record now reports a clean **Integrity: FAIL** (exit `1`).
67
+ - **Timestamp precedence:** `verification.timestamp.token` → `timestamp.token` →
68
+ bundle-embedded (`trustedTimestamps[]` / singular `timestamp`).
69
+ - **Redesigned audit-grade report** (and `--json`): **Integrity**, **Signature**,
70
+ **Timestamp** (`VERIFIED` / `INVALID (<reason>)` / `PRESENT BUT NOT VERIFIED` /
71
+ `NOT INCLUDED IN RECORD` + generation time and authority), **Node** (node id, key id,
72
+ key source, operator), **Identity**, and **Execution** (protocol, provider, model,
73
+ input/output hashes, parameters, created-at). The report now ends with a single
74
+ headline line — **`FINAL STATUS: VERIFIED EVIDENCE RECORD`** or **`FINAL STATUS:
75
+ FAILED`**.
76
+ - **New `nexart verify-url <url>`.** One-command verification: fetches a CER record (or
77
+ a bare bundle) as JSON from a URL and verifies it through the **same** automatic
78
+ key/timestamp resolution and audit-grade renderer as `verify-record`. The payload is
79
+ auto-detected as a full record (`verification.receipt`) or a raw bundle — both route
80
+ through the rich verifier. The URL fetch is the record *source* and always runs;
81
+ `--offline` here only disables the separate signing-key auto-fetch. Bad HTTP status,
82
+ network errors, and non-JSON bodies fail cleanly with exit `1`.
83
+ - **New `nexart verify-hash <certificate_hash>`.** Resolves a record straight from its
84
+ certificate hash: constructs the public node lookup URL
85
+ (`https://node.nexart.io/v1/cer/public?certificate_hash=<hash>`) and verifies it via
86
+ `verify-url`, so the output is **identical** to `verify-url`. The hash must carry the
87
+ canonical `sha256:` prefix (a missing prefix fails cleanly with exit `1` before any
88
+ network call). Supports `--short`, `--offline`, `--json` (and the rest of the
89
+ `verify-url` options). Distinct from the existing `verify <snapshot>` command, which
90
+ is left untouched.
91
+ - **New `verify-record -` (stdin).** A `-` path reads the record from standard input,
92
+ enabling pipelines such as `curl -s … | nexart verify-record -`.
93
+ - **New `--short` flag** (`verify-record` and `verify-url`): prints only a single
94
+ verdict line — `✔ VERIFIED` or `✖ FAILED`.
95
+ - **Unchanged invariants:** the timestamp layer never modifies `certificateHash`, is
96
+ never canonicalised, and **never affects the Integrity/Signature result or the exit
97
+ code** (`0` only when integrity passes and the signature is not invalid, `1`
98
+ otherwise). Operational TSA errors (untrusted root, imprint mismatch, unreadable
99
+ `--tsa-roots`) are reported as a timestamp *status*, never a crash. `verify-bundle`
100
+ remains **byte-for-byte unchanged**.
101
+
3
102
  ## v0.15.1 (2026-06-17) — docs: correct README version header
4
103
 
5
104
  Docs-only patch. No code or behaviour changes.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @nexart/cli v0.15.1
1
+ # @nexart/cli v0.16.1
2
2
 
3
3
  Command-line interface for NexArt — run, replay, and verify deterministic generative art, plus AI execution certification commands.
4
4
 
@@ -34,7 +34,9 @@ authenticity without relying on NexArt systems or source code.
34
34
  ### What this verifies
35
35
 
36
36
  - **Integrity** — the record's `certificateHash` is recomputed from the record's
37
- contents and compared to the stored value.
37
+ contents and compared to the stored value. A privacy-redacted public record
38
+ (input/output content stripped, hashes kept) is reported as **AUTHENTIC
39
+ (REDACTED)** rather than failed — see the [3-state model](#verifying-a-full-cer-record-nexart-verify-record).
38
40
  - **Authenticity** — the Ed25519 signature over the node's receipt is verified,
39
41
  when a signature is present.
40
42
 
@@ -691,13 +693,16 @@ nexart verify-bundle cer.json --verify-timestamp --tsa-roots tsa-roots.pem
691
693
  not established.
692
694
 
693
695
  3. **Timestamp (RFC 3161)** *(optional, additive — `--verify-timestamp`)* — when
694
- the bundle carries an RFC 3161 TimeStampToken (in `trustedTimestamps[]` or a
696
+ the bundle carries an RFC 3161 timestamp (in `trustedTimestamps[]` or a
695
697
  singular `timestamp`), this **offline** check confirms the token anchors the
696
- bundle to a point in time. It verifies, in order: (1) the TSA's CMS signature
697
- over the embedded `TSTInfo`; (2) that the token's message imprint equals the
698
- bundle's `certificateHash` digest; (3) that the TSA signing certificate chains
699
- to a root supplied via `--tsa-roots`; (4) that the certificate is valid at the
700
- timestamp; and (5) that the timestamp is at or after the bundle's `createdAt`.
698
+ bundle to a point in time. Both wire shapes are accepted: a full
699
+ `TimeStampResp` (the certification node's output) and a bare `TimeStampToken`
700
+ (e.g. OpenSSL's `-token_out`) the response wrapper is detected and unwrapped
701
+ automatically. It verifies, in order: (1) the TSA's CMS signature over the
702
+ embedded `TSTInfo`; (2) that the token's message imprint equals the bundle's
703
+ `certificateHash` digest; (3) that the TSA signing certificate chains to a root
704
+ supplied via `--tsa-roots`; (4) that the certificate is valid at the timestamp;
705
+ and (5) that the timestamp is at or after the bundle's `createdAt`.
701
706
 
702
707
  This layer is **strictly additive**: it never modifies `certificateHash`, is
703
708
  never included in canonicalisation, and **never affects the Integrity or
@@ -798,35 +803,183 @@ optional externally anchored timestamp:
798
803
  }
799
804
  ```
800
805
 
801
- **How it differs from `verify-bundle`.** `verify-bundle` takes a bundle whose
802
- receipt and signature are already embedded inside it. `verify-record` accepts the
803
- record envelope above, lifts `verification.receipt` / `verification.receiptSignature`
804
- onto the bundle, and then runs the **exact same** integrity + signature checks as
805
- `verify-bundle` (it reuses the identical internal verifier — no duplicated crypto).
806
- The record-level `timestamp.token` takes precedence over any token embedded in the
807
- bundle; if the record omits it, an embedded `trustedTimestamps[]` / `timestamp` is
808
- used instead. Everything else — flags, output, exit-code semantics — is identical
809
- to `verify-bundle`.
806
+ **Fully automatic since v0.16.0.** Give it a record file and nothing else the
807
+ command verifies integrity, the receipt signature, **and** the RFC 3161 timestamp
808
+ automatically, and prints an audit-grade report. It is self-contained: a third party
809
+ needs only the record and this CLI.
810
810
 
811
811
  ```bash
812
- # Integrity + signature of a full record (offline)
813
- nexart verify-record record.json --public-key node-keys.json
812
+ # Full automatic verification: integrity + signature + timestamp
813
+ nexart verify-record record.json
814
814
 
815
- # Machine-readable output
816
- nexart verify-record record.json --public-key node-keys.json --json
815
+ # Machine-readable report
816
+ nexart verify-record record.json --json
817
+
818
+ # Read the record from stdin (use "-" as the path)
819
+ curl -s https://node.example/records/abc.json | nexart verify-record -
820
+
821
+ # One-line verdict only (✔ VERIFIED / ⚠ AUTHENTIC (REDACTED) / ✖ FAILED)
822
+ nexart verify-record record.json --short
823
+
824
+ # Fully offline, with an explicit signing key
825
+ nexart verify-record record.json --offline --public-key node-keys.json
826
+ ```
827
+
828
+ **Flexible input.** The bundle is taken from `record.bundle` when present, or the
829
+ record root is treated as the bundle itself (a certified bundle with its receipt and
830
+ signature embedded works directly). There is no "missing bundle" error — a
831
+ structurally invalid record simply reports a clean **Integrity: FAIL**.
832
+
833
+ **Three-state model (since v0.16.1).** A public record served from a node may be
834
+ **privacy-redacted**: the snapshot's `input` / `output` *content* is stripped while the
835
+ `inputHash` / `outputHash` anchors are kept. Because `certificateHash` is sealed over the
836
+ full snapshot, it can no longer be recomputed from a redacted snapshot — but that is
837
+ **not tampering**. `verify-record` (and `verify-url` / `verify-hash`) detect this case and
838
+ report a third outcome:
839
+
840
+ | Outcome | When | Integrity line | Exit |
841
+ | --- | --- | --- | --- |
842
+ | **VERIFIED** | content present, `certificateHash` recomputes, signature not invalid | `✔ Integrity: PASS` | `0` |
843
+ | **AUTHENTIC (REDACTED)** | content stripped (hashes kept), recompute not possible, signature **passes** | `⚠ Integrity: NOT RECOMPUTABLE (redacted)` | `0` |
844
+ | **FAILED** | a real integrity mismatch (content present but hash differs) or an invalid signature | `✖ Integrity: FAIL` | `1` |
845
+
846
+ A redacted record is reclassified **only** when the snapshot is genuinely content-stripped
847
+ *and* the signature still verifies — a true content mismatch is **never** softened to
848
+ redacted, an invalid signature is always **FAILED**, and a redacted record whose hash still
849
+ recomputes simply stays **VERIFIED**. The `certificateHash` computation, canonicalisation,
850
+ and signature/timestamp logic are **unchanged**; this is purely a classification and
851
+ presentation layer.
852
+
853
+ > **What AUTHENTIC (REDACTED) does and does not prove.** It proves the record carries a
854
+ > valid node signature over the sealed `certificateHash` — i.e. it is authentic. It does
855
+ > **not** recompute the full snapshot, so it cannot prove the *content* behind the kept
856
+ > `inputHash` / `outputHash` was not altered before redaction. Redaction detection is
857
+ > structural (content absent, hashes present), so treat **AUTHENTIC (REDACTED)** as
858
+ > trustworthy only when the record comes from an authenticated node source (e.g. the
859
+ > node's public endpoint over TLS). For the strongest guarantee, obtain the full,
860
+ > un-redacted record and re-run `verify-record` to get **VERIFIED**.
861
+
862
+ **Signing key resolution (by priority).**
863
+
864
+ 1. **`--public-key <file>`** — an explicit override (PEM, JWK, NodeKeysDocument, or
865
+ raw base64url).
866
+ 2. **Auto-fetch** — otherwise the node's published key set is fetched from
867
+ `https://node.nexart.io/.well-known/nexart-node.json` and the key whose `kid`
868
+ matches the receipt's `attestorKeyId` is used. This is the **only** network call
869
+ in the verify path; it lives entirely in the CLI layer (the auditable core never
870
+ touches the network) and fails gracefully — a network error just falls through to
871
+ the next source. Override the URL with `NEXART_NODE_WELLKNOWN_URL`, or disable the
872
+ fetch entirely with **`--offline`**.
873
+ 3. **Embedded key** — a key embedded in the bundle, if any.
874
+
875
+ **Automatic timestamp verification.** An RFC 3161 token at
876
+ `verification.timestamp.token`, `timestamp.token`, or embedded in the bundle is
877
+ verified automatically and offline against an **embedded DigiCert trust store**
878
+ (DigiCert Trusted Root G4 + DigiCert Assured ID Root CA). Override the trusted roots
879
+ with **`--tsa-roots <file>`** (PEM). The ASN.1 stack (`pkijs` / `asn1js`) loads
880
+ **only** when a token is actually present. The timestamp layer is **strictly
881
+ additive**: it never modifies `certificateHash`, is never canonicalised, and **never
882
+ affects the Integrity / Signature result or the exit code** (which is `0` only when
883
+ integrity passes and the signature is not invalid, `1` otherwise) — an
884
+ untrusted-root, imprint-mismatch, or unreadable-`--tsa-roots` outcome is reported as
885
+ a timestamp *status*, never a crash.
886
+
887
+ **Input from a file or stdin.** Pass a file path, or **`-`** to read the record from
888
+ standard input — handy for pipelines such as `curl -s … | nexart verify-record -`.
889
+
890
+ **Report.** The default output is an audit-grade summary rendered in a fixed section
891
+ order — **Signature**, **Integrity**, **Timestamp** (`VERIFIED` / `INVALID (<reason>)` /
892
+ `PRESENT BUT NOT VERIFIED` / `NOT INCLUDED`, plus generation time and authority),
893
+ **Node** (node id, key id, key source, operator), **Identity** (asserted identity, or
894
+ none), and **Execution** (protocol, provider, model, input/output hashes, parameters,
895
+ created-at). A present-but-unverifiable token (a parse failure, or verification not
896
+ attempted) is shown as a caution — `⚠ Timestamp: PRESENT BUT NOT VERIFIED` — never as an
897
+ error, and the timestamp **never** affects `FINAL STATUS`. The report ends with a single
898
+ headline line — **`FINAL STATUS: VERIFIED EVIDENCE RECORD`**, **`FINAL STATUS: AUTHENTIC
899
+ (REDACTED)`**, or **`FINAL STATUS: FAILED`**. For a redacted record the Signature line is
900
+ shown before the Integrity line and a tight context block follows the headline:
901
+
902
+ ```
903
+ FINAL STATUS: AUTHENTIC (REDACTED)
904
+ Mode: Public Verification (Redacted)
905
+ Redaction: Applied by certification node (privacy mode)
906
+ ! Full integrity verification requires access to original execution data
907
+ ```
908
+
909
+ `--json` emits the same information as a structured object (with `status` of `verified` /
910
+ `authentic-redacted` / `failed`, `integrity` including `redacted`, and a `redacted`
911
+ boolean); `--short` prints only `✔ VERIFIED`, `⚠ AUTHENTIC (REDACTED)`, or `✖ FAILED`.
912
+
913
+ | Option | Description |
914
+ | --- | --- |
915
+ | `--public-key <file>` | Override the signing key. Default: auto-fetched from the node `.well-known` key set. |
916
+ | `--offline` | Do not contact the network; use `--public-key` or a bundle-embedded key only. |
917
+ | `--kid <id>` | Key id to select from the key set (default: the receipt's `attestorKeyId`). |
918
+ | `--tsa-roots <file>` | Override the default DigiCert TSA trust roots with custom root certificate(s) (PEM). |
919
+ | `--json` | Emit a machine-readable report. |
920
+ | `--short` | Print only a single verdict line (`✔ VERIFIED` / `⚠ AUTHENTIC (REDACTED)` / `✖ FAILED`). |
921
+ | `--verbose` | Show intermediate verification steps. |
922
+
923
+ > **`verify-bundle` is unchanged.** The redesigned output and automatic key/timestamp
924
+ > resolution apply to `verify-record` only;
925
+ > [`verify-bundle`](#independent-verification-nexart-verify-bundle) keeps its existing
926
+ > behaviour, flags, and byte-for-byte output.
927
+
928
+ ---
929
+
930
+ ## Verifying from a URL (`nexart verify-url`)
931
+
932
+ `nexart verify-url <url>` is the one-command verification experience: it **fetches** a
933
+ CER record (or a bare bundle) as JSON from a URL and verifies it with the exact same
934
+ automatic key/timestamp resolution and audit-grade renderer as `verify-record`.
817
935
 
818
- # Additionally verify the record's RFC 3161 timestamp against trusted TSA roots
819
- nexart verify-record record.json --public-key node-keys.json \
820
- --verify-timestamp --tsa-roots tsa-roots.pem
936
+ ```bash
937
+ # Fetch and fully verify a published record
938
+ nexart verify-url https://node.example/records/abc.json
939
+
940
+ # One-line verdict (✔ VERIFIED / ⚠ AUTHENTIC (REDACTED) / ✖ FAILED)
941
+ nexart verify-url https://node.example/records/abc.json --short
942
+
943
+ # Machine-readable report
944
+ nexart verify-url https://node.example/records/abc.json --json
945
+ ```
946
+
947
+ The response is auto-detected as a **full record** (has `verification.receipt`) or a
948
+ **raw bundle**; both route through the same rich verifier (a bare bundle is accepted
949
+ directly). The URL fetch is the record *source* and always happens; **`--offline`**
950
+ here only disables the separate signing-key auto-fetch (so pair it with `--public-key`
951
+ or rely on a bundle-embedded key). A non-2xx response, a network error, or a
952
+ non-JSON body fails cleanly with exit `1`. All other options match `verify-record`
953
+ (`--public-key`, `--kid`, `--tsa-roots`, `--json`, `--short`, `--verbose`).
954
+
955
+ ---
956
+
957
+ ## Verifying by certificate hash (`nexart verify-hash`)
958
+
959
+ `nexart verify-hash <certificate_hash>` resolves a CER record straight from its
960
+ certificate hash. It constructs the public node lookup URL
961
+ (`https://node.nexart.io/v1/cer/public?certificate_hash=<hash>`) and then verifies it
962
+ through `verify-url`, so the **output is identical** to `verify-url`.
963
+
964
+ ```bash
965
+ # Resolve and fully verify a record by certificate hash
966
+ nexart verify-hash sha256:abc123…
967
+
968
+ # One-line verdict (✔ VERIFIED / ⚠ AUTHENTIC (REDACTED) / ✖ FAILED)
969
+ nexart verify-hash sha256:abc123… --short
970
+
971
+ # Machine-readable report
972
+ nexart verify-hash sha256:abc123… --json
821
973
  ```
822
974
 
823
- The **Integrity**, **Signature**, **Timestamp** semantics, the human-readable and
824
- `--json` shapes, and the option table are all exactly as documented for
825
- [`verify-bundle`](#independent-verification-nexart-verify-bundle) above. The
826
- timestamp layer is, identically, **strictly additive**: `pkijs` is loaded **only**
827
- under `--verify-timestamp`, and the timestamp result **never** affects the
828
- Integrity/Signature outcome or the process exit code (which is `0` only when
829
- integrity passes and the signature is not invalid, `1` otherwise).
975
+ The hash **must** include the canonical `sha256:` prefix; a missing prefix fails
976
+ cleanly with exit `1` (before any network call). Network failures behave exactly like
977
+ `verify-url`. Options match `verify-url` (`--public-key`, `--kid`, `--tsa-roots`,
978
+ `--json`, `--short`, `--offline`, `--verbose`); as with `verify-url`, `--offline` only
979
+ disables the signing-key auto-fetch the record itself is always fetched.
980
+
981
+ > Note: this is distinct from `nexart verify <snapshot>`, which verifies that a
982
+ > snapshot reproduces its expected output.
830
983
 
831
984
  ---
832
985
 
package/dist/index.d.ts CHANGED
@@ -220,27 +220,62 @@ export declare function verifyBundleStandaloneCommand(file: string, opts: {
220
220
  /**
221
221
  * nexart verify-record — Verify a full NexArt CER RECORD offline and independently.
222
222
  *
223
- * A "record" is the full verification envelope: { bundle, verification: { receipt,
224
- * receiptSignature }, timestamp? }. This command is STRICTLY ADDITIVE alongside
225
- * `verify-bundle` and reuses the exact same engine:
223
+ * A "record" is the full verification envelope. v0.16.0 makes this command fully
224
+ * automatic, audit-grade, and self-contained a third party needs only the record
225
+ * file and this CLI:
226
+ * - FLEXIBLE PARSING: the bundle is taken from `record.bundle` when present, or the
227
+ * record root is treated as the bundle itself. There is no "missing bundle" error;
228
+ * a structurally invalid record simply reports a clean Integrity FAIL.
226
229
  * - INTEGRITY + SIGNATURE: the record's `verification.receipt` /
227
- * `verification.receiptSignature` are merged into a SHALLOW copy of `bundle`
228
- * (which never affects the recomputed certificateHash receipt/signature are
229
- * not part of the certificate payload) and handed to verifyBundleStandalone().
230
- * Behaviour, including --public-key / --kid, is identical to verify-bundle.
231
- * - TIMESTAMP (optional, additive): the record-level `timestamp.token` (or a
232
- * bundle-embedded timestamp) is verified via the same resolveTimestampResult()
233
- * path used by verify-bundle. It NEVER affects integrity, signature, or the
234
- * exit code, and the ASN.1 stack loads only behind --verify-timestamp.
230
+ * `verification.receiptSignature` are merged into a SHALLOW copy of the bundle
231
+ * (which never affects the recomputed certificateHash) and handed to
232
+ * verifyBundleStandalone(). The signing public key is, by priority:
233
+ * 1. `--public-key <file>` (explicit override), else
234
+ * 2. auto-fetched from the node's published key set at
235
+ * https://node.nexart.io/.well-known/nexart-node.json, selecting the key
236
+ * whose kid matches the receipt's attestorKeyId (skipped under --offline),
237
+ * else
238
+ * 3. key material embedded in the bundle, if any.
239
+ * - TIMESTAMP (automatic): an RFC 3161 token at `verification.timestamp.token`,
240
+ * `timestamp.token`, or embedded in the bundle is verified automatically and
241
+ * offline against the embedded DigiCert trust store (override with --tsa-roots).
242
+ * The ASN.1 stack loads only when a token is actually present. The timestamp
243
+ * NEVER affects Integrity, Signature, or the exit code.
244
+ *
245
+ * Exit code: 0 when integrity passes and signature is not a failure, 1 otherwise.
235
246
  */
236
- export declare function verifyRecordStandaloneCommand(file: string, opts: {
247
+ export interface RecordVerifyOpts {
237
248
  publicKey?: string;
238
249
  kid?: string;
239
250
  json?: boolean;
240
251
  verbose?: boolean;
241
- verifyTimestamp?: boolean;
242
252
  tsaRoots?: string;
243
- }): Promise<StandaloneVerifyResult>;
253
+ offline?: boolean;
254
+ wellKnownUrl?: string;
255
+ short?: boolean;
256
+ }
257
+ export declare function verifyRecordStandaloneCommand(file: string, opts: RecordVerifyOpts): Promise<StandaloneVerifyResult>;
258
+ /**
259
+ * Verify an already-parsed CER record (or bare bundle) object and render the
260
+ * audit-grade report. This is the shared core behind `verify-record` (file / stdin)
261
+ * and `verify-url` (network), so key resolution, timestamp verification, and the rich
262
+ * renderer behave identically across all input sources.
263
+ */
264
+ export declare function verifyRecordFromObject(record: unknown, opts: RecordVerifyOpts): Promise<StandaloneVerifyResult>;
265
+ /**
266
+ * nexart verify-url — Fetch a CER record (or bare bundle) from a URL and verify it
267
+ * automatically, using the SAME rich renderer and key/timestamp resolution as
268
+ * `verify-record`. The single network fetch here is the record SOURCE; `--offline`
269
+ * still disables the (separate) signing-key auto-fetch, exactly as for verify-record.
270
+ */
271
+ export declare function verifyUrlCommand(url: string, opts: RecordVerifyOpts): Promise<StandaloneVerifyResult>;
272
+ /**
273
+ * nexart verify-hash — Resolve a certificate hash to its public CER record URL and verify it.
274
+ * This is a thin convenience wrapper over `verify-url`: it constructs
275
+ * `${PUBLIC_CER_ENDPOINT}?certificate_hash=<hash>` and delegates, so the output is
276
+ * identical to `verify-url`. The hash must carry the canonical `sha256:` prefix.
277
+ */
278
+ export declare function verifyHashCommand(certificateHash: string, opts: RecordVerifyOpts): Promise<StandaloneVerifyResult>;
244
279
  /**
245
280
  * Render the human-readable timestamp STATUS line WITHOUT importing the ASN.1 stack.
246
281
  * This deliberately mirrors formatTsaLine() in tsaVerify.ts but lives here so the
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAcH,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAGL,cAAc,IAAI,iBAAiB,EAqBpC,MAAM,sBAAsB,CAAC;AAi0B9B;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAerD;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,WAAW,GAAE,MAAM,OAAO,CAAC,MAAM,CAAiB,GACjD,OAAO,CAAC,OAAO,CAAC,CA0BlB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,EACb,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,GAAE,OAAO,KAAwB,GACvC,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAoB5C;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,0BAAoB,CAAC;AAEhD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,EAAE,CAwB9D;AAoED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE;IACJ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,EACD,WAAW,GAAE,MAAM,OAAO,CAAC,MAAM,CAAiB,GACjD,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE;IACJ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,EACD,OAAO,GAAE,OAAO,KAAwB,EACxC,WAAW,GAAE,MAAM,OAAO,CAAC,MAAM,CAAiB,GACjD,OAAO,CAAC,IAAI,CAAC,CA8Cf;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE;IACJ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,EACD,OAAO,GAAE,OAAO,KAAwB,EACxC,WAAW,GAAE,MAAM,OAAO,CAAC,MAAM,CAAiB,GACjD,OAAO,CAAC,IAAI,CAAC,CA8Df;AAqCD,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,EAChE,WAAW,GAAE,MAAM,OAAO,CAAC,MAAM,CAAiB,GACjD,OAAO,CAAC,IAAI,CAAC,CA+Hf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACrB,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EAC7D,WAAW,GAAE,MAAM,OAAO,CAAC,MAAM,CAAiB,GACjD,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1H,OAAO,CAAC,sBAAsB,CAAC,CAqCjC;AAiHD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,sBAAsB,CAAC,CAKjC;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,sBAAsB,CAAC,CAuHjC;AAyBD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,sBAAsB,CAAC,CA6BjC;AAeD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,sBAAsB,CAAC,CASjC;AAqTD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,gBAAgB,EAAE,SAAS,GAAG,MAAM,CAyBtF;AAmDD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,EACvB,WAAW,GAAE,MAAM,OAAO,CAAC,MAAM,CAAiB,GACjD,OAAO,CAAC,IAAI,CAAC,CAwBf"}