@nexart/cli 0.16.1 → 1.1.0
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 +45 -0
- package/README.md +38 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +81 -11
- package/dist/index.js.map +1 -1
- package/dist/skills/nexart-cli.d.ts +295 -0
- package/dist/skills/nexart-cli.d.ts.map +1 -0
- package/dist/skills/nexart-cli.js +488 -0
- package/dist/skills/nexart-cli.js.map +1 -0
- package/dist/standaloneVerify.d.ts.map +1 -1
- package/dist/standaloneVerify.js +3 -2
- package/dist/standaloneVerify.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# @nexart/cli — Changelog
|
|
2
2
|
|
|
3
|
+
## v1.1.0 (2026-06-29) — protocolVersion 1.3.1 (Confidential Execution) support
|
|
4
|
+
|
|
5
|
+
> **Additive, backward-compatible.** Aligns the CLI with `@nexart/ai-execution@^1.2.0`
|
|
6
|
+
> so it can seal and verify `protocolVersion 1.3.1` (Confidential Execution) records.
|
|
7
|
+
> `1.3.1` is bound to `jcs-v1` — byte-for-byte identical canonicalisation to `1.3.0` —
|
|
8
|
+
> so there is **no** change to hashing, signatures, exit codes, or the verification of
|
|
9
|
+
> existing `1.2.0` / `1.3.0` records. The CLI continues to implement zero independent
|
|
10
|
+
> verification logic beyond the audited standalone canonicaliser.
|
|
11
|
+
|
|
12
|
+
### What changed
|
|
13
|
+
- **Standalone offline verifier** (`standaloneVerify.ts`): `canonicalModeForProtocol`
|
|
14
|
+
now binds `1.3.1 → jcs-v1`. Previously it was fail-closed on any unknown
|
|
15
|
+
`protocolVersion`, so a `1.3.1` bundle could not be verified offline.
|
|
16
|
+
- **`ai seal --protocol-version`**: the accepted values now include `1.3.1` (CLI
|
|
17
|
+
`choices` + the seal skill-tool `enum`); the fail-closed override message lists it.
|
|
18
|
+
- **Dependency:** bumped `@nexart/ai-execution` to `^1.2.0`.
|
|
19
|
+
|
|
20
|
+
## v1.0.0 (2026-06-18) — First stable release (includes `verify-offline`)
|
|
21
|
+
|
|
22
|
+
> **Stabilisation release.** Marks the `@nexart/cli` command surface stable under
|
|
23
|
+
> semantic versioning. No cryptographic, hashing, canonicalisation, or exit-code
|
|
24
|
+
> change. Builds on `@nexart/ai-execution@^1.0.0` and `@nexart/codemode-sdk@^1.12.0`,
|
|
25
|
+
> both stable. The CLI continues to implement **zero** independent verification logic —
|
|
26
|
+
> it delegates entirely to the SDK verification core. The `verify-offline` command
|
|
27
|
+
> introduced for this release (below) is the only functional addition.
|
|
28
|
+
|
|
29
|
+
### Included in this release
|
|
30
|
+
The new `verify-offline` command — a UX-only entry point over the existing offline
|
|
31
|
+
verification path:
|
|
32
|
+
|
|
33
|
+
- **New `verify-offline <record.json>` command.** A convenience alias for
|
|
34
|
+
`verify-record --offline`: it runs the **same** verification core (integrity via
|
|
35
|
+
certificate-hash recompute, Ed25519 receipt signature, timestamp reporting) and
|
|
36
|
+
**never contacts a NexArt node**. The signing key comes from `--keys` (an alias for
|
|
37
|
+
`--public-key`) or a key embedded in the record. Reads from a file path or `-` (stdin).
|
|
38
|
+
- **Offline report labelling.** A passing record prints
|
|
39
|
+
**`FINAL STATUS: AUTHENTIC (OFFLINE)`** with an explicit **`Mode: Offline Verification`**
|
|
40
|
+
line (the redaction note is still appended for privacy-redacted records). A real
|
|
41
|
+
integrity mismatch or invalid signature stays **`FINAL STATUS: FAILED`** with exit `1`.
|
|
42
|
+
`--json` gains an additive `"mode": "offline"` field; online output is unchanged.
|
|
43
|
+
- **No new verification logic.** Hashing, the version-dispatched `canonicalForProtocol()`
|
|
44
|
+
canonicalisation, the 3-state core, and exit codes are byte-for-byte identical to
|
|
45
|
+
`verify-record`. As before, a missing or unverifiable timestamp is *reported* but never
|
|
46
|
+
gates the verdict or exit code. `verify-bundle` is untouched.
|
|
47
|
+
|
|
3
48
|
## v0.16.1 (2026-06-17) — `verify-record`: 3-state verification (VERIFIED / AUTHENTIC (REDACTED) / FAILED)
|
|
4
49
|
|
|
5
50
|
UX release. `verify-bundle` is **byte-for-byte unchanged**; the new third state applies
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @nexart/cli
|
|
1
|
+
# @nexart/cli v1.0.0
|
|
2
2
|
|
|
3
3
|
Command-line interface for NexArt — run, replay, and verify deterministic generative art, plus AI execution certification commands.
|
|
4
4
|
|
|
@@ -927,6 +927,43 @@ boolean); `--short` prints only `✔ VERIFIED`, `⚠ AUTHENTIC (REDACTED)`, or `
|
|
|
927
927
|
|
|
928
928
|
---
|
|
929
929
|
|
|
930
|
+
## Offline verification (`nexart verify-offline`)
|
|
931
|
+
|
|
932
|
+
`nexart verify-offline <record.json>` is a convenience alias for
|
|
933
|
+
`verify-record --offline` for relying parties who want a single, unambiguous
|
|
934
|
+
"verify this locally, never touch the network" command. It runs the **exact same**
|
|
935
|
+
verification core — integrity (certificate-hash recompute), Ed25519 receipt
|
|
936
|
+
signature, and timestamp reporting — and **never contacts a NexArt node**. The
|
|
937
|
+
signing key must come from `--keys` (an alias for `--public-key`) or be embedded in
|
|
938
|
+
the record.
|
|
939
|
+
|
|
940
|
+
```bash
|
|
941
|
+
# Verify a record locally with an explicit node key file
|
|
942
|
+
nexart verify-offline record.json --keys node-keys.json
|
|
943
|
+
|
|
944
|
+
# Verify a record that embeds its own signing key
|
|
945
|
+
nexart verify-offline record.json
|
|
946
|
+
|
|
947
|
+
# Read the record from stdin
|
|
948
|
+
curl -s https://node.example/records/abc.json | nexart verify-offline - --keys node-keys.json
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
It differs from `verify-record` only in presentation: a passing record reports
|
|
952
|
+
**`FINAL STATUS: AUTHENTIC (OFFLINE)`** with an explicit **`Mode: Offline
|
|
953
|
+
Verification`** line (the redaction note is still appended for a privacy-redacted
|
|
954
|
+
record), while a real mismatch or invalid signature stays **`FINAL STATUS:
|
|
955
|
+
FAILED`** with exit `1`. `--json` adds `"mode": "offline"`. **Hashing,
|
|
956
|
+
canonicalisation, the 3-state core, and exit codes are identical to
|
|
957
|
+
`verify-record`** — this is a UX wrapper, not new verification logic. As with
|
|
958
|
+
`verify-record`, a missing or unverifiable timestamp is *reported* but never
|
|
959
|
+
changes the verdict or exit code.
|
|
960
|
+
|
|
961
|
+
> **This verifies authenticity and integrity, not re-execution.** A pass confirms
|
|
962
|
+
> the record was signed by a NexArt node and has not been tampered with; it does
|
|
963
|
+
> **not** re-run the workload.
|
|
964
|
+
|
|
965
|
+
---
|
|
966
|
+
|
|
930
967
|
## Verifying from a URL (`nexart verify-url`)
|
|
931
968
|
|
|
932
969
|
`nexart verify-url <url>` is the one-command verification experience: it **fetches** a
|
package/dist/index.d.ts
CHANGED
|
@@ -253,6 +253,7 @@ export interface RecordVerifyOpts {
|
|
|
253
253
|
offline?: boolean;
|
|
254
254
|
wellKnownUrl?: string;
|
|
255
255
|
short?: boolean;
|
|
256
|
+
offlineMode?: boolean;
|
|
256
257
|
}
|
|
257
258
|
export declare function verifyRecordStandaloneCommand(file: string, opts: RecordVerifyOpts): Promise<StandaloneVerifyResult>;
|
|
258
259
|
/**
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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":"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"}
|
package/dist/index.js
CHANGED
|
@@ -876,7 +876,7 @@ function buildSealInputs(raw, protocolVersionOverride) {
|
|
|
876
876
|
// error names the flag rather than surfacing a generic SDK schema error.
|
|
877
877
|
if (protocolVersionOverride !== undefined) {
|
|
878
878
|
if (!isSupportedProtocolVersion(protocolVersionOverride)) {
|
|
879
|
-
console.error(`[nexart] Error: Unsupported --protocol-version "${protocolVersionOverride}". Supported versions: 1.2.0 (nexart-v1), 1.3.0 (jcs-v1 / RFC 8785).`);
|
|
879
|
+
console.error(`[nexart] Error: Unsupported --protocol-version "${protocolVersionOverride}". Supported versions: 1.2.0 (nexart-v1), 1.3.0 (jcs-v1 / RFC 8785), 1.3.1 (jcs-v1 / confidential).`);
|
|
880
880
|
process.exit(1);
|
|
881
881
|
}
|
|
882
882
|
snapshotParams.protocolVersion = protocolVersionOverride;
|
|
@@ -1801,6 +1801,7 @@ function renderRecordVerification(result, tsaResult, ctx) {
|
|
|
1801
1801
|
if (ctx.opts.json) {
|
|
1802
1802
|
process.stdout.write(JSON.stringify({
|
|
1803
1803
|
status: result.status,
|
|
1804
|
+
...(ctx.opts.offlineMode ? { mode: 'offline' } : {}),
|
|
1804
1805
|
integrity: result.integrity,
|
|
1805
1806
|
redacted: result.integrity === 'redacted',
|
|
1806
1807
|
signature: result.signature,
|
|
@@ -1899,16 +1900,29 @@ function renderRecordVerification(result, tsaResult, ctx) {
|
|
|
1899
1900
|
if (str(ctx.bundle.createdAt))
|
|
1900
1901
|
console.log(` Created: ${str(ctx.bundle.createdAt)}`);
|
|
1901
1902
|
// ── Final verdict line (3-state) ──
|
|
1903
|
+
// `verify-offline` (offlineMode) is a DISPLAY wrapper: a non-failed record is labelled
|
|
1904
|
+
// "AUTHENTIC (OFFLINE)" regardless of the redacted/verified split, while a failure stays
|
|
1905
|
+
// "FAILED". The 3-state core, exit code, and crypto are untouched.
|
|
1906
|
+
const offline = ctx.opts.offlineMode === true;
|
|
1902
1907
|
console.log('');
|
|
1903
|
-
console.log(result.status === '
|
|
1904
|
-
? 'FINAL STATUS:
|
|
1905
|
-
:
|
|
1906
|
-
? 'FINAL STATUS: AUTHENTIC (
|
|
1907
|
-
:
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
//
|
|
1911
|
-
|
|
1908
|
+
console.log(result.status === 'failed'
|
|
1909
|
+
? 'FINAL STATUS: FAILED'
|
|
1910
|
+
: offline
|
|
1911
|
+
? 'FINAL STATUS: AUTHENTIC (OFFLINE)'
|
|
1912
|
+
: result.status === 'verified'
|
|
1913
|
+
? 'FINAL STATUS: VERIFIED EVIDENCE RECORD'
|
|
1914
|
+
: 'FINAL STATUS: AUTHENTIC (REDACTED)');
|
|
1915
|
+
// Mode / context block. In offline mode an explicit "Mode: Offline Verification" line
|
|
1916
|
+
// is always shown for a passing record; the redaction note is appended when the public
|
|
1917
|
+
// record was privacy-redacted. Online keeps the original redacted-only context block.
|
|
1918
|
+
if (offline && result.status !== 'failed') {
|
|
1919
|
+
console.log('Mode: Offline Verification');
|
|
1920
|
+
if (result.status === 'authentic-redacted') {
|
|
1921
|
+
console.log('Redaction: Applied by certification node (privacy mode)');
|
|
1922
|
+
console.log('! Full integrity verification requires access to original execution data');
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
else if (result.status === 'authentic-redacted') {
|
|
1912
1926
|
console.log('Mode: Public Verification (Redacted)');
|
|
1913
1927
|
console.log('Redaction: Applied by certification node (privacy mode)');
|
|
1914
1928
|
console.log('! Full integrity verification requires access to original execution data');
|
|
@@ -2399,7 +2413,7 @@ if (_isMainModule) {
|
|
|
2399
2413
|
.option('protocol-version', {
|
|
2400
2414
|
describe: 'Canonicalisation protocol version for the sealed CER. Overrides any protocolVersion in the input JSON.',
|
|
2401
2415
|
type: 'string',
|
|
2402
|
-
choices: ['1.2.0', '1.3.0'],
|
|
2416
|
+
choices: ['1.2.0', '1.3.0', '1.3.1'],
|
|
2403
2417
|
})
|
|
2404
2418
|
.example('$0 ai seal execution.json', 'Seal locally and print bundle JSON')
|
|
2405
2419
|
.example('cat execution.json | $0 ai seal --quiet | $0 ai verify', 'Seal then verify in a pipe')
|
|
@@ -2597,6 +2611,62 @@ if (_isMainModule) {
|
|
|
2597
2611
|
offline: argv.offline,
|
|
2598
2612
|
tsaRoots: argv['tsa-roots'],
|
|
2599
2613
|
});
|
|
2614
|
+
})
|
|
2615
|
+
.command('verify-offline <file>', 'Verify a CER record locally without contacting a NexArt node (offline-only alias of verify-record --offline)', (yargs) => {
|
|
2616
|
+
return yargs
|
|
2617
|
+
.positional('file', {
|
|
2618
|
+
describe: 'Path to the CER record JSON, or "-" to read it from stdin ({ bundle, verification?, timestamp? } or a bare bundle)',
|
|
2619
|
+
type: 'string',
|
|
2620
|
+
demandOption: true,
|
|
2621
|
+
})
|
|
2622
|
+
.option('keys', {
|
|
2623
|
+
alias: 'public-key',
|
|
2624
|
+
describe: 'Node public key(s) for signature verification (PEM, JWK, NodeKeysDocument, or raw base64url). Falls back to a key embedded in the record',
|
|
2625
|
+
type: 'string',
|
|
2626
|
+
})
|
|
2627
|
+
.option('kid', {
|
|
2628
|
+
describe: 'Key id to select from the key set (default: the receipt attestorKeyId)',
|
|
2629
|
+
type: 'string',
|
|
2630
|
+
})
|
|
2631
|
+
.option('json', {
|
|
2632
|
+
describe: 'Output machine-readable JSON',
|
|
2633
|
+
type: 'boolean',
|
|
2634
|
+
default: false,
|
|
2635
|
+
})
|
|
2636
|
+
.option('short', {
|
|
2637
|
+
describe: 'Print only a single verdict line (✔ VERIFIED / ⚠ AUTHENTIC (REDACTED) / ✖ FAILED)',
|
|
2638
|
+
type: 'boolean',
|
|
2639
|
+
default: false,
|
|
2640
|
+
})
|
|
2641
|
+
.option('verbose', {
|
|
2642
|
+
describe: 'Show intermediate verification steps',
|
|
2643
|
+
type: 'boolean',
|
|
2644
|
+
default: false,
|
|
2645
|
+
})
|
|
2646
|
+
.option('tsa-roots', {
|
|
2647
|
+
describe: 'Override the default DigiCert TSA trust roots with custom root certificate(s) (PEM)',
|
|
2648
|
+
type: 'string',
|
|
2649
|
+
})
|
|
2650
|
+
.example('$0 verify-offline record.json --keys node-keys.json', 'Fully offline verification with an explicit key file')
|
|
2651
|
+
.example('$0 verify-offline record.json', 'Offline verification using a key embedded in the record')
|
|
2652
|
+
.epilogue('This verifies that the record was signed by a NexArt node and has not been tampered with. ' +
|
|
2653
|
+
'It does not re-execute the workload, and never contacts a node.');
|
|
2654
|
+
}, async (argv) => {
|
|
2655
|
+
// yargs collapses a bare "-" positional to an empty string; restore the stdin sentinel.
|
|
2656
|
+
const file = argv.file === '' ? '-' : argv.file;
|
|
2657
|
+
await verifyRecordStandaloneCommand(file, {
|
|
2658
|
+
// `keys` is the alias for `public-key`; yargs populates both, prefer either.
|
|
2659
|
+
publicKey: argv.keys ?? argv['public-key'],
|
|
2660
|
+
kid: argv.kid,
|
|
2661
|
+
json: argv.json,
|
|
2662
|
+
short: argv.short,
|
|
2663
|
+
verbose: argv.verbose,
|
|
2664
|
+
tsaRoots: argv['tsa-roots'],
|
|
2665
|
+
// verify-offline is offline by definition: no network for keys or anything else.
|
|
2666
|
+
offline: true,
|
|
2667
|
+
// Display-only: label the report as an offline verification.
|
|
2668
|
+
offlineMode: true,
|
|
2669
|
+
});
|
|
2600
2670
|
})
|
|
2601
2671
|
.command('verify-hash <certificate_hash>', 'Resolve a certificate hash to its public CER record and verify it — one-command verification', (yargs) => {
|
|
2602
2672
|
return yargs
|