assertledger 1.3.1 → 1.5.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/README.fr.md +6 -3
- package/README.md +6 -3
- package/conformance/schema-extensions.json +15 -0
- package/dist/build-info.json +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +218 -8
- package/dist/cli.js.map +1 -1
- package/dist/contracts/index.d.ts +467 -4
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +256 -3
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/qualification.d.ts +528 -0
- package/dist/contracts/qualification.d.ts.map +1 -0
- package/dist/contracts/qualification.js +357 -0
- package/dist/contracts/qualification.js.map +1 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +46 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/qualification.d.ts +17 -0
- package/dist/core/qualification.d.ts.map +1 -0
- package/dist/core/qualification.js +571 -0
- package/dist/core/qualification.js.map +1 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +81 -4
- package/dist/diagnostics.js.map +1 -1
- package/dist/engine/adapters/bun-native.d.ts +35 -0
- package/dist/engine/adapters/bun-native.d.ts.map +1 -0
- package/dist/engine/adapters/bun-native.js +179 -0
- package/dist/engine/adapters/bun-native.js.map +1 -0
- package/dist/engine/adapters/bun-test-designated-profile.d.ts +23 -0
- package/dist/engine/adapters/bun-test-designated-profile.d.ts.map +1 -0
- package/dist/engine/adapters/bun-test-designated-profile.js +24 -0
- package/dist/engine/adapters/bun-test-designated-profile.js.map +1 -0
- package/dist/engine/container.d.ts +7 -0
- package/dist/engine/container.d.ts.map +1 -1
- package/dist/engine/container.js +22 -7
- package/dist/engine/container.js.map +1 -1
- package/dist/engine/git-regression.d.ts.map +1 -1
- package/dist/engine/git-regression.js +9 -2
- package/dist/engine/git-regression.js.map +1 -1
- package/dist/engine/index.d.ts +14 -0
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +828 -97
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/qualification.d.ts +154 -0
- package/dist/engine/qualification.d.ts.map +1 -0
- package/dist/engine/qualification.js +725 -0
- package/dist/engine/qualification.js.map +1 -0
- package/dist/engine/test-closure.d.ts +39 -0
- package/dist/engine/test-closure.d.ts.map +1 -0
- package/dist/engine/test-closure.js +513 -0
- package/dist/engine/test-closure.js.map +1 -0
- package/dist/engine/witness-import.d.ts +31 -0
- package/dist/engine/witness-import.d.ts.map +1 -0
- package/dist/engine/witness-import.js +224 -0
- package/dist/engine/witness-import.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +65 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/sdk/index.d.ts +292 -3
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +39 -1
- package/dist/sdk/index.js.map +1 -1
- package/docs/container-isolation.md +6 -0
- package/docs/migration-orchestration-qualification-v1.md +109 -0
- package/docs/migration-verification-v4.md +94 -0
- package/docs/orchestration-qualification.md +167 -0
- package/docs/reference.md +13 -0
- package/docs/witness-import.md +67 -0
- package/examples/orchestration/README.md +68 -0
- package/examples/orchestration/consumer-obligations.json +101 -0
- package/examples/orchestration/workspace/bitbucket-pipelines.yml +10 -0
- package/examples/orchestration/workspace/command-shape.test.mjs +25 -0
- package/examples/orchestration/workspace/commands.mjs +14 -0
- package/examples/orchestration/workspace/completion.mjs +39 -0
- package/examples/orchestration/workspace/faults.json +1 -0
- package/examples/orchestration/workspace/native.test.ts +4 -0
- package/examples/orchestration/workspace/package.json +6 -0
- package/examples/orchestration/workspace/packages/app/package.json +12 -0
- package/examples/orchestration/workspace/packages/app/verdict.txt +1 -0
- package/examples/orchestration/workspace/packages/leaf/package.json +9 -0
- package/examples/orchestration/workspace/packages/leaf/verdict.txt +1 -0
- package/examples/orchestration/workspace/pnpm-lock.yaml +170 -0
- package/examples/orchestration/workspace/pnpm-workspace.yaml +2 -0
- package/examples/orchestration/workspace/task.mjs +23 -0
- package/examples/orchestration/workspace/turbo.json +38 -0
- package/examples/orchestration/workspace/wrapper.mjs +45 -0
- package/integrations/bun/driver.d.mts +30 -1
- package/integrations/bun/driver.mjs +215 -6
- package/integrations/bun/preload.mjs +186 -5
- package/integrations/bun-native/README.md +86 -0
- package/integrations/bun-native/driver.mjs +396 -0
- package/integrations/bun-native/preload.mjs +375 -0
- package/integrations/skill/SKILL.md +25 -5
- package/package.json +1 -1
- package/schemas/evidence-manifest.v4.json +995 -0
- package/schemas/qualification-execution-request.v1.json +571 -0
- package/schemas/qualification-plan.v1.json +528 -0
- package/schemas/qualification-receipt.v1.json +821 -0
- package/schemas/qualification-replay-result.v1.json +37 -0
- package/schemas/verification-request.v4.json +590 -0
- package/schemas/witness-import-request.v1.json +231 -0
package/README.fr.md
CHANGED
|
@@ -9,12 +9,12 @@ Vous obtenez un verdict, les observations qui le justifient et un fichier de pre
|
|
|
9
9
|
|
|
10
10
|
[Essayer l’exemple](#essayer-lexemple) · [Comprendre le résultat](#comprendre-le-résultat) · [Utiliser votre dépôt](#utiliser-votre-dépôt) · [Documentation](#documentation)
|
|
11
11
|
|
|
12
|
-
**1.
|
|
12
|
+
**1.4 · node:test et bun:test · CLI, SDK et MCP · MIT**
|
|
13
13
|
|
|
14
14
|
Installez l’outil dans votre dépôt avec Node.js 22.15 ou une version ultérieure :
|
|
15
15
|
|
|
16
16
|
```sh
|
|
17
|
-
npm install --save-dev assertledger@1.
|
|
17
|
+
npm install --save-dev assertledger@1.5.0
|
|
18
18
|
npx assertledger doctor .
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -60,7 +60,7 @@ flowchart LR
|
|
|
60
60
|
Prérequis : **Git**, **Node.js 22.15+** et **pnpm 11.1.2**. L’exemple utilise l’adaptateur intégré `node:test`.
|
|
61
61
|
|
|
62
62
|
```sh
|
|
63
|
-
git clone --branch v1.
|
|
63
|
+
git clone --branch v1.5.0 https://github.com/hoklims/assertledger.git
|
|
64
64
|
cd assertledger
|
|
65
65
|
pnpm install --frozen-lockfile
|
|
66
66
|
pnpm build
|
|
@@ -181,6 +181,9 @@ L’adaptateur cible précisément Bun 1.4.2 et attribue les échecs de cet outi
|
|
|
181
181
|
natifs restent des erreurs d’exécution et ne comptent pas comme détection du défaut. Le
|
|
182
182
|
[guide de migration Bun](docs/migration-verification-v3.md) décrit la requête, l’exécution et le
|
|
183
183
|
rejeu. Ce mode exécute du code local de confiance sans bac à sable.
|
|
184
|
+
Pour vérifier un test `bun:test` existant désigné par son nom, ou rejouer un témoin rouge/vert
|
|
185
|
+
enregistré, utilisez une requête v4 ou `import-witness`, qui s’exécutent aussi en conteneur ou dans un
|
|
186
|
+
mode Windows natif déclaré ; voir le [guide de migration v4](docs/migration-verification-v4.md).
|
|
184
187
|
|
|
185
188
|
### Qualifier un test de régression commité
|
|
186
189
|
|
package/README.md
CHANGED
|
@@ -9,12 +9,12 @@ You get a verdict, the observations behind it and an evidence file you can repla
|
|
|
9
9
|
|
|
10
10
|
[Try the example](#try-the-example) · [Understand the result](#understand-the-result) · [Use your repository](#use-your-repository) · [Documentation](#documentation)
|
|
11
11
|
|
|
12
|
-
**1.
|
|
12
|
+
**1.4 · node:test and bun:test · CLI, SDK and MCP · MIT**
|
|
13
13
|
|
|
14
14
|
Install in your repository with Node.js 22.15 or later:
|
|
15
15
|
|
|
16
16
|
```sh
|
|
17
|
-
npm install --save-dev assertledger@1.
|
|
17
|
+
npm install --save-dev assertledger@1.5.0
|
|
18
18
|
npx assertledger doctor .
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -59,7 +59,7 @@ flowchart LR
|
|
|
59
59
|
You need **Git**, **Node.js 22.15+** and **pnpm 11.1.2**. The example uses the built-in `node:test` adapter.
|
|
60
60
|
|
|
61
61
|
```sh
|
|
62
|
-
git clone --branch v1.
|
|
62
|
+
git clone --branch v1.5.0 https://github.com/hoklims/assertledger.git
|
|
63
63
|
cd assertledger
|
|
64
64
|
pnpm install --frozen-lockfile
|
|
65
65
|
pnpm build
|
|
@@ -173,6 +173,9 @@ The Bun adapter pins version 1.4.2 and attributes failures from this helper. Nat
|
|
|
173
173
|
failures remain operational failures and cannot count as target detection. See the
|
|
174
174
|
[Bun migration guide](docs/migration-verification-v3.md) for the request, execution and replay
|
|
175
175
|
contract. The execution mode is explicitly unsandboxed and intended for trusted local code.
|
|
176
|
+
To verify an existing `bun:test` test by name, or to replay a recorded red/green witness, use a v4
|
|
177
|
+
request or `import-witness`, which also run in a container or a declared Windows-native backend; see
|
|
178
|
+
the [v4 migration guide](docs/migration-verification-v4.md).
|
|
176
179
|
|
|
177
180
|
### Qualify a committed regression test
|
|
178
181
|
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
"rawSha256": "sha256:460925ce29c51e47a38e439264f56dac9d444f52a07ec103f38b44e59679adbd",
|
|
28
28
|
"$id": "https://testforge.dev/schemas/evidence-manifest.v3.json"
|
|
29
29
|
},
|
|
30
|
+
{
|
|
31
|
+
"path": "schemas/evidence-manifest.v4.json",
|
|
32
|
+
"rawSha256": "sha256:56bad50457b84864decbe911d98e3257880e4562d69487b4a820f7d516c3d11b",
|
|
33
|
+
"$id": "https://testforge.dev/schemas/evidence-manifest.v4.json"
|
|
34
|
+
},
|
|
30
35
|
{
|
|
31
36
|
"path": "schemas/evidence-provider-manifest.v1.json",
|
|
32
37
|
"rawSha256": "sha256:6100995f772cd24b7369e4428fb1aba570f1ba6e1f61295bc42a1f7ce6b5bde3",
|
|
@@ -56,6 +61,16 @@
|
|
|
56
61
|
"path": "schemas/verification-request.v3.json",
|
|
57
62
|
"rawSha256": "sha256:3b88e4c58425aa9a45da330b27f4a48d778c1f9a2494ac2a9a4c01b29728fd77",
|
|
58
63
|
"$id": "https://testforge.dev/schemas/verification-request.v3.json"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"path": "schemas/verification-request.v4.json",
|
|
67
|
+
"rawSha256": "sha256:f08389ef40c7d73d7f1c2006aee2efcd2bf53c8b78338883f4bc9f21808db842",
|
|
68
|
+
"$id": "https://testforge.dev/schemas/verification-request.v4.json"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"path": "schemas/witness-import-request.v1.json",
|
|
72
|
+
"rawSha256": "sha256:ec2aa94fd0d50e6dec7ff6f6b9bea294febf8d7ba4598e01fe89177f97348974",
|
|
73
|
+
"$id": "https://testforge.dev/schemas/witness-import-request.v1.json"
|
|
59
74
|
}
|
|
60
75
|
]
|
|
61
76
|
}
|
package/dist/build-info.json
CHANGED
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAcA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAOlD,OAAO,EAAgD,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAYlG,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,eAAe,CAAC;IACzC,cAAc,CAAC,EAAE,OAAO,cAAc,CAAC;CACxC;AAkrBD,wBAAsB,MAAM,CAC1B,IAAI,EAAE,MAAM,EAAE,EACd,EAAE,EAAE,KAAK,EACT,YAAY,GAAE,eAAoB,GACjC,OAAO,CAAC,MAAM,CAAC,CAs7BjB"}
|
package/dist/cli.js
CHANGED
|
@@ -4,12 +4,14 @@ import path from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
6
6
|
import { ContractError } from "./contracts/index.js";
|
|
7
|
-
import {
|
|
7
|
+
import { QualificationExpectedDomainSchema } from "./contracts/qualification.js";
|
|
8
|
+
import { quoteRepositoryEntry, renderDiagnostics, renderRepositoryLinkRefusal, } from "./diagnostics.js";
|
|
8
9
|
import { connectClient, disconnectClient } from "./engine/connection.js";
|
|
9
10
|
import { parseContainerRuntimeCommand } from "./engine/container.js";
|
|
10
11
|
import { runFixtureDemo } from "./engine/demo.js";
|
|
11
12
|
import { renderGitRegressionSummary, } from "./engine/git-regression.js";
|
|
12
13
|
import { setupRepository } from "./engine/setup.js";
|
|
14
|
+
import { DEFAULT_WITNESS_ENVIRONMENT_ALLOWLIST } from "./engine/witness-import.js";
|
|
13
15
|
import { AgenticCorpusError, evaluateAgenticCorpusHoldout, evaluateAgenticCorpusPublic, inspectAgenticCorpus, } from "./evaluation/agentic-corpus.js";
|
|
14
16
|
import { createAssertLedgerServer } from "./mcp/index.js";
|
|
15
17
|
import { AssertLedger } from "./sdk/index.js";
|
|
@@ -58,9 +60,21 @@ Commands:
|
|
|
58
60
|
evidence-provider-manifest|evidence-export-request|evidence-export|
|
|
59
61
|
evidence-export-replay-result>
|
|
60
62
|
Print a JSON Schema
|
|
61
|
-
verify [request.json|-] [--container-runtime JSON_ARGV | --allow-unsafe-execution
|
|
62
|
-
|
|
63
|
+
verify [request.json|-] [--container-runtime JSON_ARGV | --allow-unsafe-execution
|
|
64
|
+
| --allow-windows-native-execution] Execute a v2-v4 container, trusted-local or
|
|
65
|
+
declared Windows-native campaign
|
|
66
|
+
import-witness [request.json|-] --out DIRECTORY
|
|
67
|
+
(--container-image NAME@sha256:DIGEST [--container-runtime JSON_ARGV]
|
|
68
|
+
| --allow-unsafe-execution | --allow-windows-native-execution)
|
|
69
|
+
[--env NAME ...] [--json] Replay a recorded red/green witness
|
|
63
70
|
replay [manifest.json|-] Verify an evidence digest
|
|
71
|
+
qualification-plan [plan.json|-] Seal an operator-owned obligation inventory
|
|
72
|
+
qualify [request.json|-] --allow-unsafe-execution
|
|
73
|
+
Execute a scoped UNSANDBOXED qualification
|
|
74
|
+
qualification-replay [receipt.json|-] [--domain domain.json]
|
|
75
|
+
Replay integrity and explicit validity domain
|
|
76
|
+
qualification-ci [receipt.json|-] --observation observation.json
|
|
77
|
+
Admit an independently signed CI observation
|
|
64
78
|
export [request.json|-] Export replay-valid evidence for external consumers
|
|
65
79
|
export-replay [export.json|-] Replay an evidence export
|
|
66
80
|
provider Describe the evidence provider and its limits
|
|
@@ -106,6 +120,10 @@ function authorizeTrustedLocalExecution(request) {
|
|
|
106
120
|
},
|
|
107
121
|
};
|
|
108
122
|
}
|
|
123
|
+
/** Windows-native execution has its own operator flag; the request value alone never grants it. */
|
|
124
|
+
function authorizeWindowsNativeExecution(request) {
|
|
125
|
+
return authorizeTrustedLocalExecution(request);
|
|
126
|
+
}
|
|
109
127
|
function authorizeBenchmarkAcquisition(request) {
|
|
110
128
|
if (!isRecord(request) || !isRecord(request.verificationRequest))
|
|
111
129
|
return request;
|
|
@@ -565,6 +583,20 @@ const VALIDATION_ERROR_CODES = new Set([
|
|
|
565
583
|
"UNSUPPORTED_ADAPTER",
|
|
566
584
|
"UNSUPPORTED_ISOLATION",
|
|
567
585
|
"UNSUPPORTED_REPOSITORY_SYMLINK",
|
|
586
|
+
"REPOSITORY_LINK_IN_TEST_CLOSURE",
|
|
587
|
+
"REPOSITORY_LINK_ESCAPES_ROOT",
|
|
588
|
+
"TEST_CLOSURE_UNBOUNDED",
|
|
589
|
+
"WINDOWS_NATIVE_HOST_REQUIRED",
|
|
590
|
+
"WINDOWS_NATIVE_EXECUTION_NOT_ACKNOWLEDGED",
|
|
591
|
+
"DESIGNATED_TEST_OVERLAID",
|
|
592
|
+
"DESIGNATED_TEST_FILE_MISSING",
|
|
593
|
+
"REPOSITORY_DEPENDENCIES_EXCLUDED",
|
|
594
|
+
"WITNESS_REPOSITORY_INVALID",
|
|
595
|
+
"WITNESS_TARGET_PATH_INVALID",
|
|
596
|
+
"WITNESS_TARGET_BASE_MISMATCH",
|
|
597
|
+
"WITNESS_TARGET_UNCHANGED",
|
|
598
|
+
"WITNESS_OUTPUT_INSIDE_REPOSITORY",
|
|
599
|
+
"WITNESS_OUTPUT_EXISTS",
|
|
568
600
|
"VERIFICATION_REQUEST_REPOSITORY_MISMATCH",
|
|
569
601
|
"WORLD_BUDGET_EXCEEDED",
|
|
570
602
|
"WORLD_OVERLAY_BYTES_EXCEEDED",
|
|
@@ -598,6 +630,19 @@ function classifyError(error) {
|
|
|
598
630
|
}
|
|
599
631
|
return 5;
|
|
600
632
|
}
|
|
633
|
+
/** Names the link that refused a static diagnostic, or the computed imports that leave the closure
|
|
634
|
+
* unbounded. Repository paths are untrusted content and are quoted. */
|
|
635
|
+
function renderLinkAssessment(assessment) {
|
|
636
|
+
if (assessment === undefined)
|
|
637
|
+
return undefined;
|
|
638
|
+
if (assessment.refused !== undefined) {
|
|
639
|
+
return `Link detail: ${quoteRepositoryEntry(assessment.refused.path)} (${assessment.refused.reasonCode})`;
|
|
640
|
+
}
|
|
641
|
+
const unbounded = assessment.unbounded
|
|
642
|
+
.slice(0, 20)
|
|
643
|
+
.map((edge) => `Unbounded closure: ${quoteRepositoryEntry(edge.file)} (${edge.reason})`);
|
|
644
|
+
return [`Links outside every test closure: ${assessment.omitted.length}`, ...unbounded].join("\n");
|
|
645
|
+
}
|
|
601
646
|
export async function runCli(argv, io, dependencies = {}) {
|
|
602
647
|
const ledger = new AssertLedger();
|
|
603
648
|
const positional = argv.filter((argument) => !argument.startsWith("--"));
|
|
@@ -699,10 +744,17 @@ export async function runCli(argv, io, dependencies = {}) {
|
|
|
699
744
|
}
|
|
700
745
|
return runtimeResult.status === "READY" ? 0 : 3;
|
|
701
746
|
}
|
|
747
|
+
let linkAssessment;
|
|
702
748
|
const result = await ledger.doctor(root, {
|
|
703
749
|
...(exclude.length === 0 ? {} : { exclude }),
|
|
704
750
|
...(framework === undefined ? {} : { framework }),
|
|
751
|
+
onLinkAssessment: (assessment) => {
|
|
752
|
+
linkAssessment = assessment;
|
|
753
|
+
},
|
|
705
754
|
});
|
|
755
|
+
const linkDetail = renderLinkAssessment(linkAssessment);
|
|
756
|
+
if (linkDetail !== undefined)
|
|
757
|
+
io.writeStderr(`${linkDetail}\n`);
|
|
706
758
|
if (argv.includes("--json")) {
|
|
707
759
|
writeJson(io, result);
|
|
708
760
|
}
|
|
@@ -894,6 +946,11 @@ export async function runCli(argv, io, dependencies = {}) {
|
|
|
894
946
|
return 0;
|
|
895
947
|
}
|
|
896
948
|
case "analyze": {
|
|
949
|
+
// `--json` stays accepted: the output is always JSON and the documented invocations pass it.
|
|
950
|
+
if (argv.slice(1).some((argument) => argument.startsWith("-") && argument !== "--json")) {
|
|
951
|
+
io.writeStderr(USAGE);
|
|
952
|
+
return 64;
|
|
953
|
+
}
|
|
897
954
|
const root = path.resolve(io.cwd, positional[1] ?? ".");
|
|
898
955
|
writeJson(io, await ledger.analyze(root));
|
|
899
956
|
return 0;
|
|
@@ -1024,6 +1081,75 @@ export async function runCli(argv, io, dependencies = {}) {
|
|
|
1024
1081
|
io.writeStdout(renderGitRegressionSummary(result, options));
|
|
1025
1082
|
return decisionExitCode(result);
|
|
1026
1083
|
}
|
|
1084
|
+
case "import-witness": {
|
|
1085
|
+
const valueFlags = new Set(["--out", "--container-image", "--container-runtime", "--env"]);
|
|
1086
|
+
const booleanFlags = new Set([
|
|
1087
|
+
"--allow-unsafe-execution",
|
|
1088
|
+
"--allow-windows-native-execution",
|
|
1089
|
+
"--json",
|
|
1090
|
+
]);
|
|
1091
|
+
let input;
|
|
1092
|
+
for (let index = 1; index < argv.length; index += 1) {
|
|
1093
|
+
const argument = argv[index] ?? "";
|
|
1094
|
+
if (valueFlags.has(argument)) {
|
|
1095
|
+
const value = argv[index + 1];
|
|
1096
|
+
if (value === undefined || value.startsWith("--")) {
|
|
1097
|
+
io.writeStderr(USAGE);
|
|
1098
|
+
return 64;
|
|
1099
|
+
}
|
|
1100
|
+
index += 1;
|
|
1101
|
+
}
|
|
1102
|
+
else if (!booleanFlags.has(argument)) {
|
|
1103
|
+
if (argument.startsWith("--") || input !== undefined) {
|
|
1104
|
+
io.writeStderr(USAGE);
|
|
1105
|
+
return 64;
|
|
1106
|
+
}
|
|
1107
|
+
input = argument;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
const out = optionalFlag(argv, "--out");
|
|
1111
|
+
if (out === undefined) {
|
|
1112
|
+
io.writeStderr(USAGE);
|
|
1113
|
+
return 64;
|
|
1114
|
+
}
|
|
1115
|
+
const allowUnsafeExecution = argv.includes("--allow-unsafe-execution");
|
|
1116
|
+
const allowWindowsNative = argv.includes("--allow-windows-native-execution");
|
|
1117
|
+
const containerImage = optionalFlag(argv, "--container-image");
|
|
1118
|
+
const containerRuntime = optionalFlag(argv, "--container-runtime");
|
|
1119
|
+
const environment = repeatedFlagValues(argv, "--env");
|
|
1120
|
+
const selected = [allowUnsafeExecution, allowWindowsNative, containerImage !== undefined];
|
|
1121
|
+
if (selected.filter(Boolean).length > 1 ||
|
|
1122
|
+
(containerImage === undefined && containerRuntime !== undefined) ||
|
|
1123
|
+
(containerImage !== undefined && environment.length > 0)) {
|
|
1124
|
+
throw new TypeError("ISOLATION_MODE_CONFLICT");
|
|
1125
|
+
}
|
|
1126
|
+
if (!selected.some(Boolean)) {
|
|
1127
|
+
io.writeStderr("Refusing to replay a witness without an authorized backend: pass --container-image, " +
|
|
1128
|
+
"--allow-unsafe-execution or --allow-windows-native-execution.\n");
|
|
1129
|
+
return 4;
|
|
1130
|
+
}
|
|
1131
|
+
const environmentAllowlist = environment.length === 0 ? [...DEFAULT_WITNESS_ENVIRONMENT_ALLOWLIST] : environment;
|
|
1132
|
+
const result = await ledger.importWitness(await readJsonInput(input, io), {
|
|
1133
|
+
out: path.resolve(io.cwd, out),
|
|
1134
|
+
isolation: containerImage !== undefined
|
|
1135
|
+
? {
|
|
1136
|
+
kind: "container",
|
|
1137
|
+
image: containerImage,
|
|
1138
|
+
...(containerRuntime === undefined
|
|
1139
|
+
? {}
|
|
1140
|
+
: { runtimeCommand: parseContainerRuntimeCommand(containerRuntime) }),
|
|
1141
|
+
}
|
|
1142
|
+
: allowWindowsNative
|
|
1143
|
+
? { kind: "windows-native", environmentAllowlist }
|
|
1144
|
+
: { kind: "trusted-local", environmentAllowlist },
|
|
1145
|
+
});
|
|
1146
|
+
if (argv.includes("--json"))
|
|
1147
|
+
writeJson(io, result);
|
|
1148
|
+
else {
|
|
1149
|
+
io.writeStdout(`${await readFile(path.join(path.resolve(io.cwd, out), "summary.md"), "utf8")}`);
|
|
1150
|
+
}
|
|
1151
|
+
return decisionExitCode(result);
|
|
1152
|
+
}
|
|
1027
1153
|
case "schema": {
|
|
1028
1154
|
const name = positional[1];
|
|
1029
1155
|
if (name !== "verification-request" &&
|
|
@@ -1043,6 +1169,10 @@ export async function runCli(argv, io, dependencies = {}) {
|
|
|
1043
1169
|
name !== "replay-result" &&
|
|
1044
1170
|
name !== "agentic-benchmark-request" &&
|
|
1045
1171
|
name !== "agentic-benchmark-artifact" &&
|
|
1172
|
+
name !== "qualification-plan" &&
|
|
1173
|
+
name !== "qualification-execution-request" &&
|
|
1174
|
+
name !== "qualification-receipt" &&
|
|
1175
|
+
name !== "qualification-replay-result" &&
|
|
1046
1176
|
name !== "agentic-benchmark-replay-result" &&
|
|
1047
1177
|
name !== "agentic-benchmark-acquisition-request" &&
|
|
1048
1178
|
name !== "agentic-benchmark-acquisition-result" &&
|
|
@@ -1078,22 +1208,43 @@ export async function runCli(argv, io, dependencies = {}) {
|
|
|
1078
1208
|
case "verify": {
|
|
1079
1209
|
const request = await readJsonInput(positionalArguments(argv, new Set(["--container-runtime"]))[1], io);
|
|
1080
1210
|
const allowUnsafeExecution = argv.includes("--allow-unsafe-execution");
|
|
1211
|
+
const allowWindowsNative = argv.includes("--allow-windows-native-execution");
|
|
1081
1212
|
const runtimeArgument = optionalFlag(argv, "--container-runtime");
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1213
|
+
const isolationKind = isRecord(request) && isRecord(request.isolation) ? request.isolation.kind : undefined;
|
|
1214
|
+
const containerRequest = isolationKind === "container";
|
|
1215
|
+
const windowsNativeRequest = isolationKind === "windows-native";
|
|
1216
|
+
// Each backend has exactly one authorization; another backend's flag never stands in.
|
|
1217
|
+
if ((containerRequest && (allowUnsafeExecution || allowWindowsNative)) ||
|
|
1218
|
+
(windowsNativeRequest && (allowUnsafeExecution || runtimeArgument !== undefined)) ||
|
|
1219
|
+
(!containerRequest &&
|
|
1220
|
+
!windowsNativeRequest &&
|
|
1221
|
+
(allowWindowsNative || runtimeArgument !== undefined))) {
|
|
1086
1222
|
throw new TypeError("ISOLATION_MODE_CONFLICT");
|
|
1087
1223
|
}
|
|
1088
|
-
if (
|
|
1224
|
+
if (windowsNativeRequest && !allowWindowsNative) {
|
|
1225
|
+
io.writeStderr("Refusing WINDOWS_NATIVE_UNSANDBOXED execution without --allow-windows-native-execution.\n");
|
|
1226
|
+
return 4;
|
|
1227
|
+
}
|
|
1228
|
+
if (!containerRequest && !windowsNativeRequest && !allowUnsafeExecution) {
|
|
1089
1229
|
io.writeStderr("Refusing trusted-local execution without --allow-unsafe-execution.\n");
|
|
1090
1230
|
return 4;
|
|
1091
1231
|
}
|
|
1092
1232
|
const version2 = isRecord(request) && request.schemaVersion === "2.0.0";
|
|
1093
1233
|
const version3 = isRecord(request) && request.schemaVersion === "3.0.0";
|
|
1234
|
+
const version4 = isRecord(request) && request.schemaVersion === "4.0.0";
|
|
1094
1235
|
const runtimeOptions = runtimeArgument === undefined
|
|
1095
1236
|
? {}
|
|
1096
1237
|
: { containerRuntime: { command: parseContainerRuntimeCommand(runtimeArgument) } };
|
|
1238
|
+
if (version4) {
|
|
1239
|
+
const authorized = containerRequest
|
|
1240
|
+
? request
|
|
1241
|
+
: windowsNativeRequest
|
|
1242
|
+
? authorizeWindowsNativeExecution(request)
|
|
1243
|
+
: authorizeTrustedLocalExecution(request);
|
|
1244
|
+
const manifest = await ledger.verifyV4(authorized, runtimeOptions);
|
|
1245
|
+
writeJson(io, manifest);
|
|
1246
|
+
return decisionExitCode(manifest);
|
|
1247
|
+
}
|
|
1097
1248
|
const result = version3
|
|
1098
1249
|
? await ledger.verifyV3(containerRequest ? request : authorizeTrustedLocalExecution(request), runtimeOptions)
|
|
1099
1250
|
: containerRequest || version2
|
|
@@ -1102,6 +1253,65 @@ export async function runCli(argv, io, dependencies = {}) {
|
|
|
1102
1253
|
writeJson(io, result);
|
|
1103
1254
|
return decisionExitCode(result);
|
|
1104
1255
|
}
|
|
1256
|
+
case "qualification-plan": {
|
|
1257
|
+
if (argv.slice(1).filter((item) => item !== "--json").length > 1 ||
|
|
1258
|
+
argv.slice(1).some((item) => item.startsWith("--") && item !== "--json")) {
|
|
1259
|
+
io.writeStderr(USAGE);
|
|
1260
|
+
return 64;
|
|
1261
|
+
}
|
|
1262
|
+
writeJson(io, ledger.sealQualificationPlan(await readJsonInput(positional[1], io)));
|
|
1263
|
+
return 0;
|
|
1264
|
+
}
|
|
1265
|
+
case "qualify": {
|
|
1266
|
+
if (argv
|
|
1267
|
+
.slice(1)
|
|
1268
|
+
.some((item) => item.startsWith("--") && item !== "--allow-unsafe-execution" && item !== "--json") ||
|
|
1269
|
+
positional.length > 2) {
|
|
1270
|
+
io.writeStderr(USAGE);
|
|
1271
|
+
return 64;
|
|
1272
|
+
}
|
|
1273
|
+
if (!argv.includes("--allow-unsafe-execution")) {
|
|
1274
|
+
io.writeStderr("Refusing UNSANDBOXED qualification without --allow-unsafe-execution.\n");
|
|
1275
|
+
return 4;
|
|
1276
|
+
}
|
|
1277
|
+
const result = await ledger.qualifyOrchestration(await readJsonInput(positional[1], io), {
|
|
1278
|
+
allowUnsafeExecution: true,
|
|
1279
|
+
});
|
|
1280
|
+
writeJson(io, result);
|
|
1281
|
+
return result.decision === "QUALIFIED" ? 0 : result.decision === "OPEN" ? 3 : 2;
|
|
1282
|
+
}
|
|
1283
|
+
case "qualification-replay": {
|
|
1284
|
+
const domainPath = optionalFlag(argv, "--domain");
|
|
1285
|
+
const args = positionalArguments(argv, new Set(["--domain"]));
|
|
1286
|
+
if (args.length > 2 ||
|
|
1287
|
+
argv
|
|
1288
|
+
.slice(1)
|
|
1289
|
+
.some((item) => item.startsWith("--") && item !== "--domain" && item !== "--json")) {
|
|
1290
|
+
io.writeStderr(USAGE);
|
|
1291
|
+
return 64;
|
|
1292
|
+
}
|
|
1293
|
+
const domain = domainPath === undefined
|
|
1294
|
+
? undefined
|
|
1295
|
+
: QualificationExpectedDomainSchema.parse(await readJsonInput(domainPath, io));
|
|
1296
|
+
const result = ledger.replayQualification(await readJsonInput(args[1], io), domain);
|
|
1297
|
+
writeJson(io, result);
|
|
1298
|
+
return result.valid ? 0 : 4;
|
|
1299
|
+
}
|
|
1300
|
+
case "qualification-ci": {
|
|
1301
|
+
const observationPath = optionalFlag(argv, "--observation");
|
|
1302
|
+
const args = positionalArguments(argv, new Set(["--observation"]));
|
|
1303
|
+
if (observationPath === undefined ||
|
|
1304
|
+
args.length > 2 ||
|
|
1305
|
+
argv
|
|
1306
|
+
.slice(1)
|
|
1307
|
+
.some((item) => item.startsWith("--") && item !== "--observation" && item !== "--json")) {
|
|
1308
|
+
io.writeStderr(USAGE);
|
|
1309
|
+
return 64;
|
|
1310
|
+
}
|
|
1311
|
+
const result = ledger.admitQualificationCi(await readJsonInput(args[1], io), await readJsonInput(observationPath, io));
|
|
1312
|
+
writeJson(io, result);
|
|
1313
|
+
return result.decision === "QUALIFIED" ? 0 : result.decision === "OPEN" ? 3 : 2;
|
|
1314
|
+
}
|
|
1105
1315
|
case "replay": {
|
|
1106
1316
|
const result = ledger.replay(await readJsonInput(positional[1], io));
|
|
1107
1317
|
writeJson(io, result);
|