@kungfu-tech/buildchain 3.0.9-alpha.9 → 4.0.0-alpha.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/AGENTS.md +39 -0
- package/README.md +17 -13
- package/actions/promote-buildchain-ref/README.md +0 -10
- package/actions/release-tail/README.md +6 -10
- package/architecture/internal-capabilities.json +502 -0
- package/architecture/maintainability-baseline.json +59 -0
- package/architecture/maintainability-policy.json +1384 -0
- package/architecture/release-tail-contract-inventory.json +587 -0
- package/architecture/v3-core-mechanism-inventory.json +1043 -0
- package/architecture/v3-core-mechanism-inventory.md +67 -0
- package/architecture/v4-adopter-delivery-parity.json +47 -0
- package/architecture/v4-architecture-constitution.md +210 -0
- package/architecture/v4-bootstrap-authority.json +56 -0
- package/architecture/v4-canonical-contract-fixtures.json +105 -0
- package/architecture/v4-capability-state-machine-manifest.json +480 -0
- package/architecture/v4-capability-state-machine-manifest.schema.json +202 -0
- package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.json +830 -0
- package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.md +223 -0
- package/architecture/v4-delivery-warrant-shadow-bootstrap-plan.schema.json +318 -0
- package/architecture/v4-delivery-warrant-shadow-fixtures.json +227 -0
- package/architecture/v4-delivery-warrant-shadow-fixtures.schema.json +67 -0
- package/architecture/v4-exception-ledger.json +5 -0
- package/architecture/v4-exception-ledger.schema.json +56 -0
- package/architecture/v4-partial-mutation-recovery-qualification.json +65 -0
- package/architecture/v4-platform-stage-checkpoints.json +97 -0
- package/architecture/v4-provider-operation-journal-contract.json +113 -0
- package/architecture/v4-release-activation-shadow-domain.json +61 -0
- package/architecture/v4-release-train-parity.json +68 -0
- package/architecture/v4-rust-libnode-bridge-evaluation.json +107 -0
- package/architecture/v4-rust-libnode-bridge-spike.md +85 -0
- package/architecture/v4-stable-publication-fence.json +66 -0
- package/architecture/v4-stage-capsule-contract.json +90 -0
- package/architecture/v4-stage-capsule-qualification.json +99 -0
- package/architecture/v4-stage-capsule-resume-planner.json +52 -0
- package/architecture/v4-stage-capsule-store-contract.json +72 -0
- package/bin/buildchain.mjs +15 -10
- package/contracts/auditable-demo-scenario-v1.schema.json +1 -1
- package/contracts/buildchain-v2-residuals-v1.json +2 -2
- package/contracts/fixtures/v4-delivery-warrant-trace-v1/golden.json +158 -0
- package/contracts/fixtures/v4-delivery-warrant-trace-v1/property.json +380 -0
- package/contracts/fixtures/v4-delivery-warrant-trace-v1/replay.json +163 -0
- package/contracts/fixtures/v4-partial-mutation-recovery-v1/shared.json +155 -0
- package/contracts/fixtures/v4-provider-operation-journal-v1/shared.json +457 -0
- package/contracts/fixtures/v4-provider-readback-idempotency-v1/shared.json +682 -0
- package/contracts/fixtures/v4-release-activation-shadow-v1/shared.json +53 -0
- package/contracts/fixtures/v4-stable-publication-fence-v1/shared.json +56 -0
- package/contracts/fixtures/v4-stage-capsule-resume-v1/late-platform-failure.json +176 -0
- package/contracts/fixtures/v4-stage-capsule-store-v1/shared.json +132 -0
- package/contracts/fixtures/v4-stage-capsule-v1/shared.json +111 -0
- package/contracts/v4-canonical-contracts-v1.schema.json +182 -0
- package/contracts/v4-delivery-warrant-semantic-diff-report-v1.schema.json +284 -0
- package/contracts/v4-delivery-warrant-trace-v1.schema.json +215 -0
- package/contracts/v4-host-contract-v1.schema.json +135 -0
- package/contracts/v4-partial-mutation-recovery-v1.schema.json +168 -0
- package/contracts/v4-provider-operation-journal-v1.schema.json +381 -0
- package/contracts/v4-release-activation-shadow-v1.schema.json +186 -0
- package/contracts/v4-stable-publication-fence-v1.schema.json +125 -0
- package/contracts/v4-stage-capsule-resume-v1.schema.json +225 -0
- package/contracts/v4-stage-capsule-store-v1.schema.json +154 -0
- package/contracts/v4-stage-capsule-v1.schema.json +178 -0
- package/crates/buildchain-v4-bridge/Cargo.lock +213 -0
- package/crates/buildchain-v4-bridge/Cargo.toml +12 -0
- package/crates/buildchain-v4-bridge/src/main.rs +495 -0
- package/dist/site/agent-index.json +0 -4
- package/dist/site/artifact-schemas.json +0 -8
- package/dist/site/buildchain-contract.json +103 -397
- package/dist/site/buildchain-site.json +302 -386
- package/dist/site/capability-registry.json +9 -11
- package/dist/site/cli-registry.json +8 -53
- package/dist/site/controller-registry.json +48 -8
- package/dist/site/kfd-claims.json +129 -167
- package/dist/site/kfd-upstream-aggregate.json +9 -9
- package/dist/site/manual-registry.json +18 -49
- package/dist/site/node-api-registry.json +4345 -7345
- package/dist/site/page-registry.json +278 -346
- package/dist/site/public-surface-audit.json +85 -404
- package/dist/site/publication-authority-registry.json +11 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +3 -9
- package/dist/site/schemas/kfd-support-projection-v1.schema.json +106 -0
- package/dist/site/site-manifest.json +22 -38
- package/dist/site/workflow-registry.json +78 -35
- package/docs/MAP.md +8 -5
- package/docs/auditable-demo.md +2 -2
- package/docs/aws-us-elastic-runner-burst-plane.md +7 -59
- package/docs/cli-reference.md +15 -213
- package/docs/cli.md +14 -14
- package/docs/dev-alpha-candidate-patrol.md +3 -11
- package/docs/dev-delivery-warrant.md +29 -194
- package/docs/engineering-housekeeper.md +12 -4
- package/docs/getting-started.md +1 -1
- package/docs/install.md +5 -5
- package/docs/kfd-support.md +2 -7
- package/docs/lifecycle-protocol.md +2 -4
- package/docs/node-api-reference.md +414 -554
- package/docs/release-flow.md +31 -31
- package/docs/release-governance.md +16 -28
- package/docs/release-passport.md +2 -15
- package/docs/release-tail-contract.md +13 -6
- package/docs/release-tail-provider-plane.md +13 -19
- package/docs/release-train.md +4 -4
- package/docs/reusable-build-surface.md +14 -27
- package/docs/site-bundle-contract.md +1 -5
- package/docs/stable-candidate-patrol.md +7 -7
- package/docs/v4-canonical-contracts.md +92 -0
- package/docs/v4-delivery-warrant-read-candidate.md +73 -0
- package/docs/v4-delivery-warrant-semantic-diff.md +75 -0
- package/docs/v4-production-release.md +63 -0
- package/docs/v4-stage-capsule.md +193 -0
- package/docs/versioning.md +3 -5
- package/package.json +19 -19
- package/packages/core/adopter-delivery-gate.js +576 -0
- package/packages/core/adopter-delivery-json.js +66 -0
- package/packages/core/artifact-signing.js +0 -61
- package/packages/core/artifact-verification-envelope.js +5 -5
- package/packages/core/build-facts.js +12 -4
- package/packages/core/buildchain-agent-manuals.js +0 -2
- package/packages/core/buildchain-channel-identity.js +3 -2
- package/packages/core/buildchain-config.js +4 -69
- package/packages/core/buildchain-contract.js +232 -46
- package/packages/core/buildchain-kfd-claims.js +1 -1
- package/packages/core/channel-candidate.js +0 -8
- package/packages/core/channel-promotion-baseline.js +0 -52
- package/packages/core/controller-evidence.js +3 -4
- package/packages/core/dev-alpha-candidate-selection.js +2 -10
- package/packages/core/dev-delivery-warrant-cancellation.js +0 -1
- package/packages/core/dev-delivery-warrant-settlement.js +20 -67
- package/packages/core/dev-delivery-warrant.js +50 -138
- package/packages/core/diagnostics.js +3 -8
- package/packages/core/github-governance-authority.js +3 -1
- package/packages/core/kfd-adopter-category-driver.js +167 -0
- package/packages/core/kfd-adopter-manifest.js +47 -46
- package/packages/core/kfd-gate.js +15 -45
- package/packages/core/paper-agent-entry.js +7 -16
- package/packages/core/paper-fleet.js +2 -2
- package/packages/core/paper-repository.js +2 -3
- package/packages/core/paper-scaffold-content.js +2 -23
- package/packages/core/paper.js +11 -43
- package/packages/core/publication-reproducibility.js +4 -4
- package/packages/core/release-line-bootstrap.js +21 -8
- package/packages/core/release-passport-contract.js +5 -5
- package/packages/core/release-passport.js +20 -131
- package/packages/core/self-dogfood-version.js +48 -35
- package/packages/core/spawn-command.js +232 -8
- package/packages/core/v4-adopter-delivery-parity.js +219 -0
- package/packages/core/v4-canonical-contracts.js +284 -0
- package/packages/core/v4-delivery-warrant-fixture-runner.js +371 -0
- package/packages/core/v4-delivery-warrant-read-candidate.js +279 -0
- package/packages/core/v4-delivery-warrant-semantic-diff-gate.js +352 -0
- package/packages/core/v4-delivery-warrant-shadow-adapter.js +447 -0
- package/packages/core/v4-partial-mutation-recovery-qualification.js +395 -0
- package/packages/core/v4-platform-stage-checkpoints.js +471 -0
- package/packages/core/v4-provider-operation-journal.js +531 -0
- package/packages/core/v4-provider-readback-idempotency.js +394 -0
- package/packages/core/v4-release-activation-shadow.js +519 -0
- package/packages/core/v4-stable-publication-fence.js +357 -0
- package/packages/core/v4-stage-capsule-local-store.js +426 -0
- package/packages/core/v4-stage-capsule-qualification-campaign.js +512 -0
- package/packages/core/v4-stage-capsule-qualification.js +456 -0
- package/packages/core/v4-stage-capsule-resume-planner.js +397 -0
- package/packages/core/v4-stage-capsule-store.js +401 -0
- package/packages/core/v4-stage-capsule.js +319 -0
- package/scripts/assemble-self-publication-admission.mjs +1 -1
- package/scripts/audit-publication-control-plane.mjs +5 -5
- package/scripts/auditable-demo-bundle-verification.mjs +3 -2
- package/scripts/auditable-demo-platform.mjs +2 -2
- package/scripts/auditable-demo-renditions.mjs +1 -1
- package/scripts/auditable-demo.mjs +2 -2
- package/scripts/aws-macos-jit-controller-core.mjs +13 -346
- package/scripts/aws-macos-jit-controller-runtime.mjs +2 -210
- package/scripts/aws-macos-jit-controller.mjs +37 -275
- package/scripts/aws-macos-jit-core.mjs +3 -41
- package/scripts/aws-macos-jit.mjs +0 -12
- package/scripts/aws-windows-jit-campaign.mjs +2 -2
- package/scripts/aws-windows-jit-controller-core.mjs +1 -1
- package/scripts/aws-windows-jit-controller.mjs +3 -3
- package/scripts/build-contract-core.mjs +3 -8
- package/scripts/build-standalone-binary.mjs +3 -14
- package/scripts/buildchain-channel-router.mjs +4 -0
- package/scripts/buildchain-cli-help.mjs +7 -16
- package/scripts/buildchain-contract-lock.mjs +0 -6
- package/scripts/check-action-bundles.mjs +3 -4
- package/scripts/check-internal-architecture.mjs +7 -6
- package/scripts/check-inventory.mjs +30 -25
- package/scripts/check-v4-public-dogfood-contract.mjs +270 -0
- package/scripts/create-release-bundle.mjs +8 -4
- package/scripts/dev-alpha-candidate-patrol.mjs +1 -22
- package/scripts/dev-delivery-proof.mjs +2 -64
- package/scripts/dev-delivery-warrant.mjs +61 -86
- package/scripts/dev-pr-auto-merge.mjs +4 -30
- package/scripts/dev-pr-delivery-warrant.mjs +0 -55
- package/scripts/dispatch-artifact-signing-authority.mjs +7 -4
- package/scripts/generate-buildchain-kfd-witnesses.mjs +94 -88
- package/scripts/generate-channel-build-workflow.mjs +54 -24
- package/scripts/generate-channel-promotion-workflow.mjs +15 -6
- package/scripts/generate-site-bundle.mjs +8 -27
- package/scripts/git-fetch-process-tree.mjs +34 -1
- package/scripts/init-repo.mjs +64 -159
- package/scripts/inspect-artifact-signing-requests.mjs +0 -6
- package/scripts/locked-source-checkout.mjs +3 -4
- package/scripts/maintainability-metrics.mjs +8 -2
- package/scripts/npm-publish-dry-run.mjs +2 -2
- package/scripts/npm-publish-transaction.mjs +2 -2
- package/scripts/publication-commit-evidence.mjs +23 -69
- package/scripts/release-candidate-resolver.mjs +11 -17
- package/scripts/release-tail.mjs +3 -49
- package/scripts/resume-from-candidate-run.mjs +9 -123
- package/scripts/run-lifecycle-core.mjs +12 -13
- package/scripts/seal-artifact-signing-requests.mjs +17 -21
- package/scripts/site-capability-metadata.mjs +3 -20
- package/scripts/stable-candidate-qualification.mjs +10 -10
- package/scripts/v4-architecture.mjs +12 -2
- package/scripts/v4-bridge-bootstrap.mjs +141 -0
- package/scripts/v4-bridge-evidence.mjs +141 -0
- package/scripts/v4-host-adapter.mjs +182 -0
- package/scripts/v4-platform-stage-checkpoint-rehearsal.mjs +207 -0
- package/scripts/v4-stage-capsule-qualification.mjs +528 -0
- package/scripts/v4-stage-capsule-resume-rehearsal.mjs +57 -0
- package/scripts/v4-warrant-shadow-plan.mjs +601 -0
- package/scripts/verify-golden-path.mjs +5 -5
- package/scripts/web-surface-cloudfront-rewrite.mjs +15 -15
- package/scripts/web-surface-core.mjs +2 -8
- package/scripts/workflow-call-contract.mjs +5 -184
- package/contracts/dev-delivery-authority-v2.schema.json +0 -253
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-perspective.json +0 -16
- package/contracts/fixtures/kfd-adopter-release-v1/kfd-4-replay.json +0 -57
- package/contracts/fixtures/next-development-transition-v1/anchored-manual-waiting.json +0 -47
- package/contracts/fixtures/next-development-transition-v1/semver-auto-planned.json +0 -47
- package/contracts/fixtures/next-development-transition-v1/version-model-cases.json +0 -40
- package/contracts/next-development-request-v1.schema.json +0 -66
- package/contracts/next-development-transition-v1.schema.json +0 -292
- package/contracts/publication-rehearsal-capsule-v1.schema.json +0 -173
- package/dist/site/schemas/dev-delivery-authority-v2.schema.json +0 -442
- package/dist/site/schemas/publication-rehearsal-capsule-v1.schema.json +0 -269
- package/dist/site/schemas/release-tail-capabilities-v1.schema.json +0 -353
- package/dist/site/schemas/release-tail-provider-bindings-v1.schema.json +0 -94
- package/docs/dev-delivery-qualification-landing-adr.md +0 -137
- package/docs/next-development-transition.md +0 -119
- package/docs/publication-rehearsal.md +0 -94
- package/packages/core/buildchain-compatibility-proof.js +0 -631
- package/packages/core/dev-delivery-authority.js +0 -996
- package/packages/core/dev-delivery-native-proof.js +0 -418
- package/packages/core/dev-delivery-warrant-shadow.js +0 -502
- package/packages/core/next-development-candidate-reservation.js +0 -186
- package/packages/core/next-development-controller.js +0 -726
- package/packages/core/next-development-projection.js +0 -288
- package/packages/core/next-development-transition.js +0 -738
- package/packages/core/publication-rehearsal-projection.js +0 -173
- package/packages/core/publication-rehearsal-runtime.js +0 -921
- package/scripts/aws-macos-jit-instance-rehydrate.mjs +0 -260
- package/scripts/aws-macos-jit-source-rebind.mjs +0 -724
- package/scripts/dev-delivery-authority.mjs +0 -368
- package/scripts/dev-delivery-native-run.mjs +0 -235
- package/scripts/dev-delivery-two-phase-resume.mjs +0 -90
- package/scripts/dev-delivery-two-phase.mjs +0 -577
- package/scripts/generate-next-development-guidance.mjs +0 -49
- package/scripts/materialize-self-release-candidate-version.mjs +0 -137
- package/scripts/next-development-self-dogfood-harness.mjs +0 -409
- package/scripts/next-development-self-dogfood.mjs +0 -532
- package/scripts/next-development-transition.mjs +0 -47
- package/scripts/release-candidate-tail-reseal.mjs +0 -426
- package/templates/native-dev-delivery.yml +0 -86
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
import { runV4DeliveryWarrantTraceFixture } from "./v4-delivery-warrant-fixture-runner.js";
|
|
7
|
+
|
|
8
|
+
export const V4_DELIVERY_WARRANT_SHADOW_OBSERVATION_CONTRACT =
|
|
9
|
+
"buildchain-v4-delivery-warrant-shadow-observation/v1";
|
|
10
|
+
export const V4_DELIVERY_WARRANT_SHADOW_RESULT_CONTRACT =
|
|
11
|
+
"buildchain-v4-delivery-warrant-shadow-result/v1";
|
|
12
|
+
|
|
13
|
+
const HOST_REQUEST_CONTRACT = "kungfu-buildchain-v4-host-request";
|
|
14
|
+
const HOST_RESPONSE_CONTRACT = "kungfu-buildchain-v4-host-response";
|
|
15
|
+
const PROJECTION_CONTRACT =
|
|
16
|
+
"buildchain-v4-delivery-warrant-semantic-projection/v1";
|
|
17
|
+
const REQUIRED_CAPABILITIES = Object.freeze([
|
|
18
|
+
"canonical-input-v1",
|
|
19
|
+
"delivery-warrant-trace-projection-v1",
|
|
20
|
+
"diagnostics-v1",
|
|
21
|
+
"effects-disabled-v1",
|
|
22
|
+
"structured-result-v1",
|
|
23
|
+
]);
|
|
24
|
+
const MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
25
|
+
const MAX_TIMEOUT_MS = 30_000;
|
|
26
|
+
const RETENTION_DAYS = 90;
|
|
27
|
+
const ROOT_PATTERN = /^sha256:[0-9a-f]{64}$/u;
|
|
28
|
+
const REVISION_PATTERN = /^[0-9a-f]{40,64}$/u;
|
|
29
|
+
const root = path.resolve(
|
|
30
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
31
|
+
"../..",
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
class ShadowHostFault extends Error {
|
|
35
|
+
constructor(code, message) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "ShadowHostFault";
|
|
38
|
+
this.code = code;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function inputBytes(value) {
|
|
43
|
+
if (Buffer.isBuffer(value)) return Buffer.from(value);
|
|
44
|
+
if (value instanceof Uint8Array) return Buffer.from(value);
|
|
45
|
+
if (typeof value === "string") return Buffer.from(value, "utf8");
|
|
46
|
+
throw new TypeError("shadow input must be bytes or a UTF-8 string");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function sha256(bytes) {
|
|
50
|
+
return `sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function diagnostic(code, retryable = false) {
|
|
54
|
+
const messages = {
|
|
55
|
+
"host-cancelled": "the non-authoritative Rust projection was cancelled",
|
|
56
|
+
"host-crashed": "the non-authoritative Rust projection host exited",
|
|
57
|
+
"host-response-invalid": "the Rust host response was malformed",
|
|
58
|
+
"host-response-mismatch": "the Rust host response correlation was invalid",
|
|
59
|
+
"host-spawn-failed":
|
|
60
|
+
"the non-authoritative Rust projection host could not start",
|
|
61
|
+
"host-timeout":
|
|
62
|
+
"the non-authoritative Rust projection exceeded its bounded timeout",
|
|
63
|
+
"input-not-public-safe":
|
|
64
|
+
"shadow input was not eligible for public-safe retention",
|
|
65
|
+
"retention-failed":
|
|
66
|
+
"the caller-owned shadow observation sink rejected the observation",
|
|
67
|
+
"rust-projection-failed":
|
|
68
|
+
"the Rust host did not produce a usable projection",
|
|
69
|
+
"shadow-config-invalid":
|
|
70
|
+
"the non-authoritative shadow configuration was invalid",
|
|
71
|
+
"shadow-disabled": "the non-authoritative Rust shadow is disabled",
|
|
72
|
+
"unsupported-capability":
|
|
73
|
+
"the Rust host did not support the effect-disabled projection contract",
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
code,
|
|
77
|
+
message: messages[code] || "the Rust shadow was unavailable",
|
|
78
|
+
retryable,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function enabledByDefault(environment = process.env) {
|
|
83
|
+
return environment.BUILDCHAIN_V4_WARRANT_SHADOW === "enabled";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function publicRetention(retention = {}) {
|
|
87
|
+
if (retention.kind === "fixture") {
|
|
88
|
+
return { classification: "public-safe-fixture", publicSafe: true };
|
|
89
|
+
}
|
|
90
|
+
if (retention.kind === "captured-replay" && retention.publicSafe === true) {
|
|
91
|
+
return { classification: "public-safe-captured-replay", publicSafe: true };
|
|
92
|
+
}
|
|
93
|
+
throw new ShadowHostFault(
|
|
94
|
+
"input-not-public-safe",
|
|
95
|
+
"only fixtures and explicitly public-safe captured replays may enter shadow retention",
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function exactSource(value, label) {
|
|
100
|
+
if (typeof value !== "string" || !REVISION_PATTERN.test(value)) {
|
|
101
|
+
throw new TypeError(`${label} must be an exact lowercase Git revision`);
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function exactValidator(value) {
|
|
107
|
+
if (typeof value !== "string" || !/^[a-z0-9][a-z0-9._-]*$/u.test(value)) {
|
|
108
|
+
throw new TypeError("validatorVersion must be a public ASCII identifier");
|
|
109
|
+
}
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function retainUntil(recordedAt) {
|
|
114
|
+
const time = Date.parse(recordedAt);
|
|
115
|
+
if (!Number.isFinite(time))
|
|
116
|
+
throw new TypeError("recordedAt must be an ISO timestamp");
|
|
117
|
+
return new Date(time + RETENTION_DAYS * 24 * 60 * 60 * 1000).toISOString();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function createV4DeliveryWarrantShadowRequest(
|
|
121
|
+
bytes,
|
|
122
|
+
{ requestId = crypto.randomUUID(), timeoutMs = 5_000 } = {},
|
|
123
|
+
) {
|
|
124
|
+
if (
|
|
125
|
+
!Number.isInteger(timeoutMs) ||
|
|
126
|
+
timeoutMs < 1 ||
|
|
127
|
+
timeoutMs > MAX_TIMEOUT_MS
|
|
128
|
+
) {
|
|
129
|
+
throw new RangeError(`timeoutMs must be between 1 and ${MAX_TIMEOUT_MS}`);
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
schemaVersion: 1,
|
|
133
|
+
contract: HOST_REQUEST_CONTRACT,
|
|
134
|
+
protocolVersion: "1.0",
|
|
135
|
+
requestId,
|
|
136
|
+
command: { id: "delivery-warrant.trace-project", arguments: [] },
|
|
137
|
+
input: { encoding: "base64", bytes: inputBytes(bytes).toString("base64") },
|
|
138
|
+
requiredCapabilities: [...REQUIRED_CAPABILITIES],
|
|
139
|
+
timeoutMs,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function validateHostResponse(response, request) {
|
|
144
|
+
if (
|
|
145
|
+
!response ||
|
|
146
|
+
response.schemaVersion !== 1 ||
|
|
147
|
+
response.contract !== HOST_RESPONSE_CONTRACT ||
|
|
148
|
+
response.protocolVersion !== "1.0"
|
|
149
|
+
) {
|
|
150
|
+
throw new ShadowHostFault(
|
|
151
|
+
"host-response-invalid",
|
|
152
|
+
"unsupported host response contract",
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
if (
|
|
156
|
+
response.requestId !== request.requestId ||
|
|
157
|
+
response.command?.id !== request.command.id
|
|
158
|
+
) {
|
|
159
|
+
throw new ShadowHostFault(
|
|
160
|
+
"host-response-mismatch",
|
|
161
|
+
"host response correlation mismatch",
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
if (!Array.isArray(response.host?.capabilities)) {
|
|
165
|
+
throw new ShadowHostFault(
|
|
166
|
+
"host-response-invalid",
|
|
167
|
+
"host capabilities are missing",
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
const missing = REQUIRED_CAPABILITIES.filter(
|
|
171
|
+
(capability) => !response.host.capabilities.includes(capability),
|
|
172
|
+
);
|
|
173
|
+
if (response.status === "unsupported" || missing.length > 0) {
|
|
174
|
+
throw new ShadowHostFault(
|
|
175
|
+
"unsupported-capability",
|
|
176
|
+
"required host capability is missing",
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
if (response.status !== "ok") {
|
|
180
|
+
throw new ShadowHostFault(
|
|
181
|
+
"rust-projection-failed",
|
|
182
|
+
"Rust projection status was not ok",
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
const result = response.structuredResult;
|
|
186
|
+
if (
|
|
187
|
+
result?.projection?.schema !== PROJECTION_CONTRACT ||
|
|
188
|
+
!ROOT_PATTERN.test(String(result?.projectionRoot || ""))
|
|
189
|
+
) {
|
|
190
|
+
throw new ShadowHostFault(
|
|
191
|
+
"host-response-invalid",
|
|
192
|
+
"Rust projection shape is invalid",
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function defaultHost() {
|
|
199
|
+
return {
|
|
200
|
+
command: "cargo",
|
|
201
|
+
arguments: [
|
|
202
|
+
"run",
|
|
203
|
+
"--locked",
|
|
204
|
+
"--quiet",
|
|
205
|
+
"--manifest-path",
|
|
206
|
+
path.join(root, "crates", "buildchain-v4-contracts", "Cargo.toml"),
|
|
207
|
+
"--",
|
|
208
|
+
"host",
|
|
209
|
+
],
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function invokeV4RustShadowHost(
|
|
214
|
+
request,
|
|
215
|
+
{ command, arguments: commandArguments, cwd = root, signal } = {},
|
|
216
|
+
) {
|
|
217
|
+
const selected = defaultHost();
|
|
218
|
+
const executable = command || selected.command;
|
|
219
|
+
const args = commandArguments || selected.arguments;
|
|
220
|
+
return new Promise((resolve, reject) => {
|
|
221
|
+
if (signal?.aborted) {
|
|
222
|
+
reject(
|
|
223
|
+
new ShadowHostFault(
|
|
224
|
+
"host-cancelled",
|
|
225
|
+
"shadow signal was already aborted",
|
|
226
|
+
),
|
|
227
|
+
);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
let settled = false;
|
|
231
|
+
let terminationCode = "";
|
|
232
|
+
let stdoutBytes = 0;
|
|
233
|
+
const stdout = [];
|
|
234
|
+
const child = spawn(executable, args, {
|
|
235
|
+
cwd,
|
|
236
|
+
env: process.env,
|
|
237
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
238
|
+
});
|
|
239
|
+
const finish = (callback) => {
|
|
240
|
+
if (settled) return;
|
|
241
|
+
settled = true;
|
|
242
|
+
clearTimeout(timeout);
|
|
243
|
+
signal?.removeEventListener("abort", cancel);
|
|
244
|
+
callback();
|
|
245
|
+
};
|
|
246
|
+
const terminate = (code) => {
|
|
247
|
+
if (terminationCode) return;
|
|
248
|
+
terminationCode = code;
|
|
249
|
+
child.kill("SIGTERM");
|
|
250
|
+
const force = setTimeout(() => child.kill("SIGKILL"), 100);
|
|
251
|
+
force.unref?.();
|
|
252
|
+
};
|
|
253
|
+
const cancel = () => terminate("host-cancelled");
|
|
254
|
+
const timeout = setTimeout(
|
|
255
|
+
() => terminate("host-timeout"),
|
|
256
|
+
request.timeoutMs,
|
|
257
|
+
);
|
|
258
|
+
timeout.unref?.();
|
|
259
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
260
|
+
child.once("error", () => {
|
|
261
|
+
finish(() =>
|
|
262
|
+
reject(new ShadowHostFault("host-spawn-failed", "host spawn failed")),
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
child.stdout.on("data", (chunk) => {
|
|
266
|
+
stdoutBytes += chunk.length;
|
|
267
|
+
if (stdoutBytes > MAX_RESPONSE_BYTES) {
|
|
268
|
+
terminate("host-response-invalid");
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
stdout.push(chunk);
|
|
272
|
+
});
|
|
273
|
+
child.stdin.on("error", () => {
|
|
274
|
+
terminate("host-crashed");
|
|
275
|
+
});
|
|
276
|
+
child.once("close", (code) => {
|
|
277
|
+
finish(() => {
|
|
278
|
+
if (terminationCode) {
|
|
279
|
+
reject(
|
|
280
|
+
new ShadowHostFault(
|
|
281
|
+
terminationCode,
|
|
282
|
+
"shadow host terminated and reaped",
|
|
283
|
+
),
|
|
284
|
+
);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (code !== 0) {
|
|
288
|
+
reject(
|
|
289
|
+
new ShadowHostFault(
|
|
290
|
+
"host-crashed",
|
|
291
|
+
"shadow host exited before a response",
|
|
292
|
+
),
|
|
293
|
+
);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
resolve(JSON.parse(Buffer.concat(stdout).toString("utf8")));
|
|
298
|
+
} catch {
|
|
299
|
+
reject(
|
|
300
|
+
new ShadowHostFault(
|
|
301
|
+
"host-response-invalid",
|
|
302
|
+
"shadow host returned invalid JSON",
|
|
303
|
+
),
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
child.stdin.end(`${JSON.stringify(request)}\n`);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function skippedShadow(inputRoot, code) {
|
|
313
|
+
return {
|
|
314
|
+
status: "skipped",
|
|
315
|
+
authority: "typescript-v3",
|
|
316
|
+
rustAuthority: "none",
|
|
317
|
+
rustEffects: "disabled",
|
|
318
|
+
inputRoot,
|
|
319
|
+
observation: null,
|
|
320
|
+
diagnostics: [diagnostic(code)],
|
|
321
|
+
retention: { status: "not-attempted" },
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export async function runV4DeliveryWarrantShadow(
|
|
326
|
+
value,
|
|
327
|
+
{
|
|
328
|
+
enabled = enabledByDefault(),
|
|
329
|
+
invokeLegacy = runV4DeliveryWarrantTraceFixture,
|
|
330
|
+
invokeRust = invokeV4RustShadowHost,
|
|
331
|
+
host = {},
|
|
332
|
+
requestId,
|
|
333
|
+
timeoutMs = 5_000,
|
|
334
|
+
signal,
|
|
335
|
+
retention = { kind: "fixture" },
|
|
336
|
+
retain,
|
|
337
|
+
recordedAt = new Date().toISOString(),
|
|
338
|
+
sources = {},
|
|
339
|
+
} = {},
|
|
340
|
+
) {
|
|
341
|
+
const bytes = inputBytes(value);
|
|
342
|
+
const authoritativeResult = await invokeLegacy(Buffer.from(bytes));
|
|
343
|
+
const inputRoot = sha256(bytes);
|
|
344
|
+
if (!enabled) {
|
|
345
|
+
return {
|
|
346
|
+
schema: V4_DELIVERY_WARRANT_SHADOW_RESULT_CONTRACT,
|
|
347
|
+
authoritativeResult,
|
|
348
|
+
shadow: skippedShadow(inputRoot, "shadow-disabled"),
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
let retentionScope;
|
|
353
|
+
try {
|
|
354
|
+
retentionScope = publicRetention(retention);
|
|
355
|
+
} catch (error) {
|
|
356
|
+
return {
|
|
357
|
+
schema: V4_DELIVERY_WARRANT_SHADOW_RESULT_CONTRACT,
|
|
358
|
+
authoritativeResult,
|
|
359
|
+
shadow: skippedShadow(inputRoot, error.code || "input-not-public-safe"),
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
let sourceBinding;
|
|
364
|
+
let request;
|
|
365
|
+
try {
|
|
366
|
+
sourceBinding = {
|
|
367
|
+
typescriptRevision: exactSource(
|
|
368
|
+
sources.typescriptRevision,
|
|
369
|
+
"typescriptRevision",
|
|
370
|
+
),
|
|
371
|
+
rustRevision: exactSource(sources.rustRevision, "rustRevision"),
|
|
372
|
+
validatorVersion: exactValidator(sources.validatorVersion),
|
|
373
|
+
};
|
|
374
|
+
request = createV4DeliveryWarrantShadowRequest(bytes, {
|
|
375
|
+
requestId,
|
|
376
|
+
timeoutMs,
|
|
377
|
+
});
|
|
378
|
+
} catch {
|
|
379
|
+
return {
|
|
380
|
+
schema: V4_DELIVERY_WARRANT_SHADOW_RESULT_CONTRACT,
|
|
381
|
+
authoritativeResult,
|
|
382
|
+
shadow: skippedShadow(inputRoot, "shadow-config-invalid"),
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
let rustProjection = null;
|
|
386
|
+
let status = "observed";
|
|
387
|
+
const diagnostics = [];
|
|
388
|
+
try {
|
|
389
|
+
const response = await invokeRust(request, { ...host, signal });
|
|
390
|
+
rustProjection = validateHostResponse(response, request);
|
|
391
|
+
} catch (error) {
|
|
392
|
+
const code =
|
|
393
|
+
error instanceof ShadowHostFault ? error.code : "rust-projection-failed";
|
|
394
|
+
diagnostics.push(diagnostic(code, code === "host-timeout"));
|
|
395
|
+
status = code === "host-cancelled" ? "cancelled" : "unavailable";
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const observation = {
|
|
399
|
+
schema: V4_DELIVERY_WARRANT_SHADOW_OBSERVATION_CONTRACT,
|
|
400
|
+
authority: "typescript-v3",
|
|
401
|
+
rustAuthority: "none",
|
|
402
|
+
rustEffects: "disabled",
|
|
403
|
+
status,
|
|
404
|
+
recordedAt,
|
|
405
|
+
retainUntil: retainUntil(recordedAt),
|
|
406
|
+
retention: retentionScope,
|
|
407
|
+
input: {
|
|
408
|
+
encoding: "base64",
|
|
409
|
+
bytes: bytes.toString("base64"),
|
|
410
|
+
root: inputRoot,
|
|
411
|
+
},
|
|
412
|
+
sources: sourceBinding,
|
|
413
|
+
legacy: {
|
|
414
|
+
sourceRevision: sourceBinding.typescriptRevision,
|
|
415
|
+
projection: authoritativeResult,
|
|
416
|
+
},
|
|
417
|
+
rust: {
|
|
418
|
+
sourceRevision: sourceBinding.rustRevision,
|
|
419
|
+
projection: rustProjection,
|
|
420
|
+
},
|
|
421
|
+
diagnostics,
|
|
422
|
+
};
|
|
423
|
+
let retentionResult = { status: "returned-to-caller" };
|
|
424
|
+
if (retain) {
|
|
425
|
+
try {
|
|
426
|
+
await retain(structuredClone(observation));
|
|
427
|
+
retentionResult = { status: "retained" };
|
|
428
|
+
} catch {
|
|
429
|
+
diagnostics.push(diagnostic("retention-failed", true));
|
|
430
|
+
retentionResult = { status: "failed" };
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
schema: V4_DELIVERY_WARRANT_SHADOW_RESULT_CONTRACT,
|
|
435
|
+
authoritativeResult,
|
|
436
|
+
shadow: {
|
|
437
|
+
status,
|
|
438
|
+
authority: "typescript-v3",
|
|
439
|
+
rustAuthority: "none",
|
|
440
|
+
rustEffects: "disabled",
|
|
441
|
+
inputRoot,
|
|
442
|
+
observation,
|
|
443
|
+
diagnostics,
|
|
444
|
+
retention: retentionResult,
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
}
|