@b00dea/cockpit 0.0.0-bootstrap.0 → 0.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 +375 -0
- package/LICENSE +21 -0
- package/README.md +21 -1
- package/bin/cockpit.mjs +33 -0
- package/cockpit.schema.json +2574 -0
- package/dist/autonomy.d.ts +44 -0
- package/dist/autonomy.js +156 -0
- package/dist/bounded-read.d.ts +14 -0
- package/dist/bounded-read.js +42 -0
- package/dist/browser/commands.d.ts +62 -0
- package/dist/browser/commands.js +349 -0
- package/dist/browser/package-paths.d.ts +1 -0
- package/dist/browser/package-paths.js +6 -0
- package/dist/browser/proxy.d.ts +22 -0
- package/dist/browser/proxy.js +37 -0
- package/dist/browser/runtime.d.ts +117 -0
- package/dist/browser/runtime.js +183 -0
- package/dist/browser/surfaces.d.ts +141 -0
- package/dist/browser/surfaces.js +556 -0
- package/dist/browser/ui-gate.d.ts +15 -0
- package/dist/browser/ui-gate.js +18 -0
- package/dist/cli-guard.d.ts +5 -0
- package/dist/cli-guard.js +71 -0
- package/dist/cli-main.d.ts +139 -0
- package/dist/cli-main.js +1405 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +16 -0
- package/dist/command-table.d.ts +113 -0
- package/dist/command-table.js +512 -0
- package/dist/config/load.d.ts +171 -0
- package/dist/config/load.js +345 -0
- package/dist/config/sibling-toml.d.ts +48 -0
- package/dist/config/sibling-toml.js +160 -0
- package/dist/config/surface-tools-toml.d.ts +9 -0
- package/dist/config/surface-tools-toml.js +37 -0
- package/dist/config/verified-write.d.ts +43 -0
- package/dist/config/verified-write.js +89 -0
- package/dist/diagnostics.d.ts +26 -0
- package/dist/diagnostics.js +335 -0
- package/dist/emit.d.ts +22 -0
- package/dist/emit.js +43 -0
- package/dist/entrypoint-kinds.d.ts +3 -0
- package/dist/entrypoint-kinds.js +11 -0
- package/dist/environment/application/destructive.d.ts +6 -0
- package/dist/environment/application/destructive.js +425 -0
- package/dist/environment/application/doctor.d.ts +89 -0
- package/dist/environment/application/doctor.js +235 -0
- package/dist/environment/application/guard.d.ts +43 -0
- package/dist/environment/application/guard.js +622 -0
- package/dist/environment/application/health.d.ts +134 -0
- package/dist/environment/application/health.js +379 -0
- package/dist/environment/application/lifecycle-context.d.ts +228 -0
- package/dist/environment/application/lifecycle-context.js +154 -0
- package/dist/environment/application/lifecycle-state.d.ts +25 -0
- package/dist/environment/application/lifecycle-state.js +201 -0
- package/dist/environment/application/lifecycle.d.ts +17 -0
- package/dist/environment/application/lifecycle.js +729 -0
- package/dist/environment/application/logs.d.ts +45 -0
- package/dist/environment/application/logs.js +127 -0
- package/dist/environment/application/setup.d.ts +129 -0
- package/dist/environment/application/setup.js +741 -0
- package/dist/environment/application/shared.d.ts +11 -0
- package/dist/environment/application/shared.js +61 -0
- package/dist/environment/claims.d.ts +389 -0
- package/dist/environment/claims.js +1709 -0
- package/dist/environment/codex-hook-trust.d.ts +11 -0
- package/dist/environment/codex-hook-trust.js +185 -0
- package/dist/environment/compose-environment.d.ts +1 -0
- package/dist/environment/compose-environment.js +6 -0
- package/dist/environment/compose-ownership.d.ts +21 -0
- package/dist/environment/compose-ownership.js +117 -0
- package/dist/environment/compose-topology.d.ts +117 -0
- package/dist/environment/compose-topology.js +413 -0
- package/dist/environment/contract.d.ts +489 -0
- package/dist/environment/contract.js +761 -0
- package/dist/environment/declaration.d.ts +14 -0
- package/dist/environment/declaration.js +39 -0
- package/dist/environment/destructive-composition.d.ts +29 -0
- package/dist/environment/destructive-composition.js +333 -0
- package/dist/environment/docker-daemon.d.ts +30 -0
- package/dist/environment/docker-daemon.js +78 -0
- package/dist/environment/docker-endpoint.d.ts +10 -0
- package/dist/environment/docker-endpoint.js +19 -0
- package/dist/environment/env-schema-observation.d.ts +46 -0
- package/dist/environment/env-schema-observation.js +241 -0
- package/dist/environment/evidence.d.ts +136 -0
- package/dist/environment/evidence.js +437 -0
- package/dist/environment/executable.d.ts +26 -0
- package/dist/environment/executable.js +167 -0
- package/dist/environment/generated-application/authorities.d.ts +5 -0
- package/dist/environment/generated-application/authorities.js +61 -0
- package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
- package/dist/environment/generated-application/bootstrap-skill.js +328 -0
- package/dist/environment/generated-application/check.d.ts +13 -0
- package/dist/environment/generated-application/check.js +189 -0
- package/dist/environment/generated-application/custom-surface.d.ts +26 -0
- package/dist/environment/generated-application/custom-surface.js +289 -0
- package/dist/environment/generated-application/prepare.d.ts +29 -0
- package/dist/environment/generated-application/prepare.js +276 -0
- package/dist/environment/generated-application/publication.d.ts +33 -0
- package/dist/environment/generated-application/publication.js +547 -0
- package/dist/environment/generated-application/shared.d.ts +484 -0
- package/dist/environment/generated-application/shared.js +349 -0
- package/dist/environment/generated-application/surface-observation.d.ts +4 -0
- package/dist/environment/generated-application/surface-observation.js +69 -0
- package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
- package/dist/environment/generated-application/surface-outputs.js +389 -0
- package/dist/environment/generated-application/surfaces.d.ts +3 -0
- package/dist/environment/generated-application/surfaces.js +699 -0
- package/dist/environment/generated-application/sync.d.ts +6 -0
- package/dist/environment/generated-application/sync.js +109 -0
- package/dist/environment/git-observation.d.ts +183 -0
- package/dist/environment/git-observation.js +544 -0
- package/dist/environment/health-composition.d.ts +11 -0
- package/dist/environment/health-composition.js +628 -0
- package/dist/environment/host-observation.d.ts +56 -0
- package/dist/environment/host-observation.js +52 -0
- package/dist/environment/identity.d.ts +48 -0
- package/dist/environment/identity.js +85 -0
- package/dist/environment/init-application.d.ts +308 -0
- package/dist/environment/init-application.js +697 -0
- package/dist/environment/install-policy-observation.d.ts +71 -0
- package/dist/environment/install-policy-observation.js +284 -0
- package/dist/environment/install-policy.d.ts +48 -0
- package/dist/environment/install-policy.js +96 -0
- package/dist/environment/instance.d.ts +33 -0
- package/dist/environment/instance.js +122 -0
- package/dist/environment/instruction-pointer.d.ts +19 -0
- package/dist/environment/instruction-pointer.js +144 -0
- package/dist/environment/lifecycle-composition.d.ts +29 -0
- package/dist/environment/lifecycle-composition.js +675 -0
- package/dist/environment/lifecycle-stage.d.ts +115 -0
- package/dist/environment/lifecycle-stage.js +398 -0
- package/dist/environment/lifecycle.d.ts +75 -0
- package/dist/environment/lifecycle.js +354 -0
- package/dist/environment/logs.d.ts +132 -0
- package/dist/environment/logs.js +519 -0
- package/dist/environment/observations.d.ts +46 -0
- package/dist/environment/observations.js +344 -0
- package/dist/environment/operator-application.d.ts +50 -0
- package/dist/environment/operator-application.js +155 -0
- package/dist/environment/ports.d.ts +182 -0
- package/dist/environment/ports.js +1205 -0
- package/dist/environment/posture-observation.d.ts +68 -0
- package/dist/environment/posture-observation.js +253 -0
- package/dist/environment/read-composition.d.ts +27 -0
- package/dist/environment/read-composition.js +352 -0
- package/dist/environment/readiness-composition.d.ts +38 -0
- package/dist/environment/readiness-composition.js +130 -0
- package/dist/environment/reclaim.d.ts +333 -0
- package/dist/environment/reclaim.js +1835 -0
- package/dist/environment/repository-identity.d.ts +13 -0
- package/dist/environment/repository-identity.js +108 -0
- package/dist/environment/runtime-measurement-record.d.ts +38 -0
- package/dist/environment/runtime-measurement-record.js +111 -0
- package/dist/environment/runtime-measurement.d.ts +27 -0
- package/dist/environment/runtime-measurement.js +224 -0
- package/dist/environment/runtime-probe-residue.d.ts +43 -0
- package/dist/environment/runtime-probe-residue.js +148 -0
- package/dist/environment/runtime-probe.d.ts +72 -0
- package/dist/environment/runtime-probe.js +725 -0
- package/dist/environment/runtime.d.ts +505 -0
- package/dist/environment/runtime.js +2335 -0
- package/dist/environment/seed.d.ts +16 -0
- package/dist/environment/seed.js +43 -0
- package/dist/environment/selftest-application.d.ts +86 -0
- package/dist/environment/selftest-application.js +713 -0
- package/dist/environment/sensitive.d.ts +3 -0
- package/dist/environment/sensitive.js +48 -0
- package/dist/environment/setup-observation.d.ts +62 -0
- package/dist/environment/setup-observation.js +1473 -0
- package/dist/environment/setup.d.ts +43 -0
- package/dist/environment/setup.js +176 -0
- package/dist/environment/sibling-instructions.d.ts +33 -0
- package/dist/environment/sibling-instructions.js +224 -0
- package/dist/environment/sibling-registration.d.ts +45 -0
- package/dist/environment/sibling-registration.js +538 -0
- package/dist/environment/state.d.ts +371 -0
- package/dist/environment/state.js +2013 -0
- package/dist/environment/templates.d.ts +140 -0
- package/dist/environment/templates.js +685 -0
- package/dist/environment/tool-registration.d.ts +9 -0
- package/dist/environment/tool-registration.js +96 -0
- package/dist/environment/upgrade-application.d.ts +19 -0
- package/dist/environment/upgrade-application.js +175 -0
- package/dist/environment-exec/execute.d.ts +102 -0
- package/dist/environment-exec/execute.js +1175 -0
- package/dist/environment-exec/libexec-program.d.ts +6 -0
- package/dist/environment-exec/libexec-program.js +22 -0
- package/dist/environment-exec/verified-digest.d.ts +4 -0
- package/dist/environment-exec/verified-digest.js +16 -0
- package/dist/exact-keys.d.ts +7 -0
- package/dist/exact-keys.js +15 -0
- package/dist/fix-catalogue.d.ts +32 -0
- package/dist/fix-catalogue.js +60 -0
- package/dist/freshness.d.ts +29 -0
- package/dist/freshness.js +75 -0
- package/dist/generated-environment/adopt.d.ts +16 -0
- package/dist/generated-environment/adopt.js +275 -0
- package/dist/generated-environment/command.d.ts +47 -0
- package/dist/generated-environment/command.js +75 -0
- package/dist/generated-environment/transaction.d.ts +186 -0
- package/dist/generated-environment/transaction.js +1770 -0
- package/dist/grading/evaluate.d.ts +71 -0
- package/dist/grading/evaluate.js +403 -0
- package/dist/grading/grade.d.ts +33 -0
- package/dist/grading/grade.js +57 -0
- package/dist/guards/evaluator.d.ts +113 -0
- package/dist/guards/evaluator.js +1226 -0
- package/dist/guards/harness-adapter.d.ts +17 -0
- package/dist/guards/harness-adapter.js +57 -0
- package/dist/guards/host.d.ts +8 -0
- package/dist/guards/host.js +10 -0
- package/dist/guards/invocation-parser.d.ts +66 -0
- package/dist/guards/invocation-parser.js +595 -0
- package/dist/guards/local-identity.d.ts +40 -0
- package/dist/guards/local-identity.js +123 -0
- package/dist/guards/policy-pin.d.ts +13 -0
- package/dist/guards/policy-pin.js +175 -0
- package/dist/guards/protected-locations.d.ts +62 -0
- package/dist/guards/protected-locations.js +461 -0
- package/dist/guards/read-only.d.ts +37 -0
- package/dist/guards/read-only.js +315 -0
- package/dist/init/command.d.ts +40 -0
- package/dist/init/command.js +310 -0
- package/dist/init/derive.d.ts +51 -0
- package/dist/init/derive.js +715 -0
- package/dist/init/draft.d.ts +138 -0
- package/dist/init/draft.js +1205 -0
- package/dist/init/render.d.ts +35 -0
- package/dist/init/render.js +82 -0
- package/dist/init/scaffold.d.ts +53 -0
- package/dist/init/scaffold.js +121 -0
- package/dist/invocation.d.ts +13 -0
- package/dist/invocation.js +20 -0
- package/dist/package-metadata.d.ts +9 -0
- package/dist/package-metadata.js +19 -0
- package/dist/readiness.d.ts +53 -0
- package/dist/readiness.js +88 -0
- package/dist/references/named.d.ts +24 -0
- package/dist/references/named.js +27 -0
- package/dist/refusal.d.ts +15 -0
- package/dist/refusal.js +7 -0
- package/dist/registry-derivation.d.ts +31 -0
- package/dist/registry-derivation.js +32 -0
- package/dist/registry-resolve/command.d.ts +47 -0
- package/dist/registry-resolve/command.js +226 -0
- package/dist/registry-resolve/registry.d.ts +68 -0
- package/dist/registry-resolve/registry.js +292 -0
- package/dist/registry-resolve/render-shell.d.ts +18 -0
- package/dist/registry-resolve/render-shell.js +36 -0
- package/dist/repair.d.ts +29 -0
- package/dist/repair.js +8 -0
- package/dist/schema-json.d.ts +1 -0
- package/dist/schema-json.js +177 -0
- package/dist/schema.d.ts +1322 -0
- package/dist/schema.js +934 -0
- package/dist/setup/command.d.ts +4 -0
- package/dist/setup/command.js +4 -0
- package/dist/sha256.d.ts +1 -0
- package/dist/sha256.js +4 -0
- package/dist/surfaces/adoption.d.ts +41 -0
- package/dist/surfaces/adoption.js +217 -0
- package/dist/surfaces/consumer-instructions.d.ts +20 -0
- package/dist/surfaces/consumer-instructions.js +43 -0
- package/dist/surfaces/contract.d.ts +42 -0
- package/dist/surfaces/contract.js +169 -0
- package/dist/surfaces/core-declarations.d.ts +24 -0
- package/dist/surfaces/core-declarations.js +79 -0
- package/dist/surfaces/development-markers.d.ts +1 -0
- package/dist/surfaces/development-markers.js +18 -0
- package/dist/surfaces/generator-adapter.d.ts +71 -0
- package/dist/surfaces/generator-adapter.js +809 -0
- package/dist/surfaces/harness-registry.d.ts +180 -0
- package/dist/surfaces/harness-registry.js +117 -0
- package/dist/surfaces/mcp.d.ts +95 -0
- package/dist/surfaces/mcp.js +186 -0
- package/dist/surfaces/merge.d.ts +30 -0
- package/dist/surfaces/merge.js +105 -0
- package/dist/surfaces/ownership.d.ts +190 -0
- package/dist/surfaces/ownership.js +795 -0
- package/dist/surfaces/projection.d.ts +136 -0
- package/dist/surfaces/projection.js +681 -0
- package/dist/surfaces/render.d.ts +118 -0
- package/dist/surfaces/render.js +633 -0
- package/dist/surfaces/restrictions.d.ts +130 -0
- package/dist/surfaces/restrictions.js +447 -0
- package/dist/surfaces/selftest.d.ts +162 -0
- package/dist/surfaces/selftest.js +393 -0
- package/dist/surfaces/skill-contract.d.ts +85 -0
- package/dist/surfaces/skill-contract.js +449 -0
- package/dist/surfaces/sync.d.ts +57 -0
- package/dist/surfaces/sync.js +164 -0
- package/dist/team-metadata.d.ts +41 -0
- package/dist/team-metadata.js +512 -0
- package/dist/testing/gates.d.ts +91 -0
- package/dist/testing/gates.js +182 -0
- package/dist/testing/hooks.d.ts +59 -0
- package/dist/testing/hooks.js +139 -0
- package/dist/testing/verdict.d.ts +29 -0
- package/dist/testing/verdict.js +62 -0
- package/dist/work-orders/application.d.ts +99 -0
- package/dist/work-orders/application.js +383 -0
- package/dist/work-orders/composition.d.ts +124 -0
- package/dist/work-orders/composition.js +1010 -0
- package/dist/work-orders/contract.d.ts +61 -0
- package/dist/work-orders/contract.js +122 -0
- package/dist/work-orders/store.d.ts +158 -0
- package/dist/work-orders/store.js +197 -0
- package/docs/README.md +65 -0
- package/docs/architecture.md +136 -0
- package/docs/capability-matrix.md +50 -0
- package/docs/cli-reference.md +599 -0
- package/docs/command-list.md +51 -0
- package/docs/compose-patterns.md +99 -0
- package/docs/concepts.md +171 -0
- package/docs/configuration-essentials.md +172 -0
- package/docs/configuration-reference.md +621 -0
- package/docs/environment.md +760 -0
- package/docs/extending.md +43 -0
- package/docs/faq.md +111 -0
- package/docs/getting-started.md +608 -0
- package/docs/harness-surfaces.md +433 -0
- package/docs/joining-a-team.md +76 -0
- package/docs/release-policy.md +49 -0
- package/docs/safety-and-autonomy.md +419 -0
- package/docs/troubleshooting.md +361 -0
- package/docs/tutorial.md +170 -0
- package/docs/work-and-browser.md +254 -0
- package/libexec/browser-operation.cjs +186 -0
- package/libexec/fence-marker.cjs +101 -0
- package/libexec/fence-marker.d.cts +24 -0
- package/libexec/fenced-group-runner.cjs +77 -0
- package/libexec/fenced-supervisor.cjs +137 -0
- package/libexec/generated-filesystem.cjs +731 -0
- package/libexec/install-filesystem.cjs +225 -0
- package/libexec/rulesync-generator.NOTICE.md +1112 -0
- package/libexec/rulesync-generator.cjs +743 -0
- package/libexec/surface-generator-worker.cjs +266 -0
- package/libexec/surface-output-reader.cjs +99 -0
- package/libexec/surface-scratch-cleanup.cjs +14 -0
- package/libexec/validate-harness-evidence.d.mts +183 -0
- package/libexec/validate-harness-evidence.mjs +1312 -0
- package/package.json +76 -1
- package/surfaces/README.md +33 -0
- package/surfaces/agents/evaluator.agent.md +76 -0
- package/surfaces/guards/bash-guard.sh +48 -0
- package/surfaces/guards/claude.adapter.json +25 -0
- package/surfaces/guards/codex.adapter.json +24 -0
- package/surfaces/guards/opencode.adapter.json +25 -0
- package/surfaces/references/browser.md +63 -0
- package/surfaces/references/test-data-and-personas.md +84 -0
- package/surfaces/references/testing-tiers.md +11 -0
- package/surfaces/skills/cockpit-browser.skill.md +54 -0
- package/surfaces/skills/cockpit-explain.skill.md +32 -0
- package/surfaces/skills/cockpit-fix.skill.md +37 -0
- package/surfaces/skills/cockpit-setup.skill.md +39 -0
- package/surfaces/skills/cockpit-work.skill.md +34 -0
- package/surfaces/skills/collection.json +5 -0
- package/surfaces/skills/procedures/explain.md +61 -0
- package/surfaces/skills/procedures/fix.md +81 -0
- package/surfaces/skills/procedures/setup.md +379 -0
- package/surfaces/skills/procedures/work.md +105 -0
|
@@ -0,0 +1,761 @@
|
|
|
1
|
+
import { dirname, isAbsolute, normalize } from 'node:path';
|
|
2
|
+
import { isProxy } from 'node:util/types';
|
|
3
|
+
import { isEntrypointKind } from '../entrypoint-kinds.js';
|
|
4
|
+
import { exactKeys } from '../exact-keys.js';
|
|
5
|
+
const JSON_LIMITS = { bytes: 1_048_576, nodes: 65_536, entries: 4_096, scalarBytes: 65_536, depth: 64 };
|
|
6
|
+
function reserveBytes(state, bytes) {
|
|
7
|
+
if (state.bytes + bytes > state.byteLimit)
|
|
8
|
+
return false;
|
|
9
|
+
state.bytes += bytes;
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
function snapshotJsonValue(value, state, depth) {
|
|
13
|
+
if (state.nodes >= JSON_LIMITS.nodes || depth > JSON_LIMITS.depth)
|
|
14
|
+
return undefined;
|
|
15
|
+
state.nodes += 1;
|
|
16
|
+
if (value === null || typeof value === 'boolean' || typeof value === 'number') {
|
|
17
|
+
if (typeof value === 'number' && !Number.isFinite(value))
|
|
18
|
+
return undefined;
|
|
19
|
+
const encoded = JSON.stringify(value);
|
|
20
|
+
return reserveBytes(state, Buffer.byteLength(encoded)) ? value : undefined;
|
|
21
|
+
}
|
|
22
|
+
if (typeof value === 'string') {
|
|
23
|
+
const bytes = Buffer.byteLength(value);
|
|
24
|
+
return bytes <= state.scalarLimit && reserveBytes(state, Buffer.byteLength(JSON.stringify(value))) ? value : undefined;
|
|
25
|
+
}
|
|
26
|
+
if (typeof value !== 'object' || isProxy(value) || state.ancestors.has(value))
|
|
27
|
+
return undefined;
|
|
28
|
+
if (!reserveBytes(state, 2))
|
|
29
|
+
return undefined;
|
|
30
|
+
const ancestors = state.ancestors;
|
|
31
|
+
ancestors.add(value);
|
|
32
|
+
try {
|
|
33
|
+
if (Array.isArray(value)) {
|
|
34
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
35
|
+
const keys = Reflect.ownKeys(value);
|
|
36
|
+
const length = descriptors.length.value;
|
|
37
|
+
if (typeof length !== 'number' || length > state.entryLimit || keys.length !== length + 1
|
|
38
|
+
|| keys.some((key) => typeof key !== 'string' || key !== 'length' && !/^(?:0|[1-9]\d*)$/.test(key))
|
|
39
|
+
|| !reserveBytes(state, Math.max(0, length - 1)))
|
|
40
|
+
return undefined;
|
|
41
|
+
const result = [];
|
|
42
|
+
for (let index = 0; index < length; index += 1) {
|
|
43
|
+
const descriptor = descriptors[String(index)];
|
|
44
|
+
if (descriptor === undefined || !descriptor.enumerable || !('value' in descriptor))
|
|
45
|
+
return undefined;
|
|
46
|
+
const item = snapshotJsonValue(descriptor.value, state, depth + 1);
|
|
47
|
+
if (item === undefined)
|
|
48
|
+
return undefined;
|
|
49
|
+
result.push(item);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
const prototype = Object.getPrototypeOf(value);
|
|
54
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
55
|
+
return undefined;
|
|
56
|
+
const result = Object.create(null);
|
|
57
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
58
|
+
const ownKeys = Reflect.ownKeys(value);
|
|
59
|
+
if (ownKeys.some((key) => typeof key !== 'string'))
|
|
60
|
+
return undefined;
|
|
61
|
+
const keys = ownKeys.sort();
|
|
62
|
+
if (keys.length > state.entryLimit || !reserveBytes(state, Math.max(0, keys.length - 1)))
|
|
63
|
+
return undefined;
|
|
64
|
+
for (const key of keys) {
|
|
65
|
+
const descriptor = descriptors[key];
|
|
66
|
+
if (!descriptor.enumerable || !('value' in descriptor))
|
|
67
|
+
return undefined;
|
|
68
|
+
if (Buffer.byteLength(key) > JSON_LIMITS.scalarBytes || !reserveBytes(state, Buffer.byteLength(JSON.stringify(key)) + 1))
|
|
69
|
+
return undefined;
|
|
70
|
+
const item = snapshotJsonValue(descriptor.value, state, depth + 1);
|
|
71
|
+
if (item === undefined)
|
|
72
|
+
return undefined;
|
|
73
|
+
Object.defineProperty(result, key, { enumerable: true, value: item });
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
catch { // A throwing accessor or proxy trap makes the value unsnapshottable; the caller refuses it.
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
ancestors.delete(value);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export function snapshotJson(value) {
|
|
85
|
+
return snapshotJsonWithEntryLimit(value, JSON_LIMITS.entries);
|
|
86
|
+
}
|
|
87
|
+
function snapshotJsonWithEntryLimit(value, entryLimit) {
|
|
88
|
+
return snapshotJsonValue(value, {
|
|
89
|
+
bytes: 0, nodes: 0, entryLimit, byteLimit: JSON_LIMITS.bytes,
|
|
90
|
+
scalarLimit: JSON_LIMITS.scalarBytes, ancestors: new WeakSet(),
|
|
91
|
+
}, 0);
|
|
92
|
+
}
|
|
93
|
+
export function snapshotGeneratedJson(value) {
|
|
94
|
+
return snapshotJsonValue(value, {
|
|
95
|
+
bytes: 0, nodes: 0, entryLimit: JSON_LIMITS.entries, byteLimit: 33_554_432,
|
|
96
|
+
scalarLimit: 16_777_216, ancestors: new WeakSet(),
|
|
97
|
+
}, 0);
|
|
98
|
+
}
|
|
99
|
+
const OBSERVATION_LIFECYCLE_STAGES = ['bootstrap', 'steady'];
|
|
100
|
+
const SETUP_ACTION_KINDS = ['clone', 'wire-remote', 'report'];
|
|
101
|
+
// Build tools and tool servers resolve their caches and locale from these; none carries a credential.
|
|
102
|
+
// Every other parent variable stays out of product test stages, verification commands and MCP servers,
|
|
103
|
+
// because they run repository code and the environment of an agent session routinely holds tokens.
|
|
104
|
+
export const INHERITED_TOOL_ENVIRONMENT = Object.freeze(['HOME', 'USER', 'LOGNAME', 'TMPDIR', 'LANG', 'LC_ALL', 'LC_CTYPE', 'TZ']);
|
|
105
|
+
// The only parent variables a Docker or Compose step receives: where the client finds the daemon and
|
|
106
|
+
// how it authenticates to it. Anything else could reconfigure Compose or the process it starts.
|
|
107
|
+
export const DOCKER_CLIENT_ENVIRONMENT = new Set(['PATH', 'DOCKER_HOST', 'DOCKER_CONTEXT', 'DOCKER_TLS_VERIFY', 'DOCKER_CERT_PATH']);
|
|
108
|
+
// Names that reconfigure the Docker client, the dynamic loader, Node or a shell; a stack-declared
|
|
109
|
+
// variable may never take one of them.
|
|
110
|
+
export const HOST_PROCESS_CONTROL_ENV = /^(?:DOCKER_|COMPOSE_|LD_|DYLD_|LIBPATH$|SHLIB_PATH$|NODE_OPTIONS$|NODE_PATH$|BASH_ENV$|ENV$|PATH$|IFS$)/;
|
|
111
|
+
export const OBSERVATION_PRODUCER_BYTE_LIMIT = 256;
|
|
112
|
+
export const OBSERVATION_REASON_BYTE_LIMIT = 1_024;
|
|
113
|
+
export const ENVIRONMENT_CODES = Object.freeze({
|
|
114
|
+
CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',
|
|
115
|
+
CONFIG_UNREADABLE: 'CONFIG_UNREADABLE',
|
|
116
|
+
CONFIG_ENCODING_INVALID: 'CONFIG_ENCODING_INVALID',
|
|
117
|
+
CONFIG_PARSE_INVALID: 'CONFIG_PARSE_INVALID',
|
|
118
|
+
CONFIG_SCHEMA_INVALID: 'CONFIG_SCHEMA_INVALID',
|
|
119
|
+
GENERATED_HOST_PATH_UNMOUNTED: 'GENERATED_HOST_PATH_UNMOUNTED',
|
|
120
|
+
STATE_ROOT_UNAVAILABLE: 'STATE_ROOT_UNAVAILABLE',
|
|
121
|
+
STATE_FORMAT_UNSUPPORTED: 'STATE_FORMAT_UNSUPPORTED',
|
|
122
|
+
STATE_RECORD_MALFORMED: 'STATE_RECORD_MALFORMED',
|
|
123
|
+
STATE_LOCKED: 'STATE_LOCKED',
|
|
124
|
+
STATE_DURABILITY_INDETERMINATE: 'STATE_DURABILITY_INDETERMINATE',
|
|
125
|
+
SETUP_CONFIG_REQUIRED: 'SETUP_CONFIG_REQUIRED',
|
|
126
|
+
SETUP_OPTION_DUPLICATE: 'SETUP_OPTION_DUPLICATE',
|
|
127
|
+
SETUP_POSITIONAL_UNSUPPORTED: 'SETUP_POSITIONAL_UNSUPPORTED',
|
|
128
|
+
SETUP_PATH_OUTSIDE_ROOT: 'SETUP_PATH_OUTSIDE_ROOT',
|
|
129
|
+
SETUP_PATH_SYMLINK: 'SETUP_PATH_SYMLINK',
|
|
130
|
+
SETUP_PATH_TYPE_INVALID: 'SETUP_PATH_TYPE_INVALID',
|
|
131
|
+
SETUP_PARENT_MISSING: 'SETUP_PARENT_MISSING',
|
|
132
|
+
SETUP_REMOTE_MISMATCH: 'SETUP_REMOTE_MISMATCH',
|
|
133
|
+
SETUP_REMOTE_UNRESOLVABLE: 'SETUP_REMOTE_UNRESOLVABLE',
|
|
134
|
+
SETUP_MANUAL_MISSING: 'SETUP_MANUAL_MISSING',
|
|
135
|
+
SETUP_CLONE_FAILED: 'SETUP_CLONE_FAILED',
|
|
136
|
+
SETUP_NONE_ABSENT: 'SETUP_NONE_ABSENT',
|
|
137
|
+
SETUP_NONE_DIRECTORY: 'SETUP_NONE_DIRECTORY',
|
|
138
|
+
SETUP_NONE_REPOSITORY: 'SETUP_NONE_REPOSITORY',
|
|
139
|
+
SETUP_POSTCHECK_FAILED: 'SETUP_POSTCHECK_FAILED',
|
|
140
|
+
SETUP_INSTRUCTION_POINTER_OFFERED: 'SETUP_INSTRUCTION_POINTER_OFFERED',
|
|
141
|
+
SETUP_INSTRUCTION_POINTER_INVALID: 'SETUP_INSTRUCTION_POINTER_INVALID',
|
|
142
|
+
SETUP_INSTRUCTION_FILES_OFFERED: 'SETUP_INSTRUCTION_FILES_OFFERED',
|
|
143
|
+
SETUP_INSTRUCTION_FILES_INVALID: 'SETUP_INSTRUCTION_FILES_INVALID',
|
|
144
|
+
CONFIG_CHANGED_DURING_EXECUTION: 'CONFIG_CHANGED_DURING_EXECUTION',
|
|
145
|
+
EXECUTION_SPAWN_FAILED: 'EXECUTION_SPAWN_FAILED',
|
|
146
|
+
EXECUTION_PRECONDITION_CHANGED: 'EXECUTION_PRECONDITION_CHANGED',
|
|
147
|
+
EXECUTION_STAGING_FAILED: 'EXECUTION_STAGING_FAILED',
|
|
148
|
+
EXECUTION_STAGING_CLEANUP_FAILED: 'EXECUTION_STAGING_CLEANUP_FAILED',
|
|
149
|
+
EXECUTION_TIMEOUT: 'EXECUTION_TIMEOUT',
|
|
150
|
+
EXECUTION_STDOUT_LIMIT: 'EXECUTION_STDOUT_LIMIT',
|
|
151
|
+
EXECUTION_STDERR_LIMIT: 'EXECUTION_STDERR_LIMIT',
|
|
152
|
+
EXECUTION_STEP_FAILED: 'EXECUTION_STEP_FAILED',
|
|
153
|
+
EXECUTION_ABORTED: 'EXECUTION_ABORTED',
|
|
154
|
+
EXECUTION_TERMINATION_UNCONFIRMED: 'EXECUTION_TERMINATION_UNCONFIRMED',
|
|
155
|
+
EXECUTION_COMPENSATION_TIMEOUT: 'EXECUTION_COMPENSATION_TIMEOUT',
|
|
156
|
+
EXECUTION_COMPENSATION_STEP_FAILED: 'EXECUTION_COMPENSATION_STEP_FAILED',
|
|
157
|
+
LIFECYCLE_EVIDENCE_INVALID: 'LIFECYCLE_EVIDENCE_INVALID',
|
|
158
|
+
LIFECYCLE_PROGRESS_INVALID: 'LIFECYCLE_PROGRESS_INVALID',
|
|
159
|
+
STACK_RECORDED_UNDER_EARLIER_NAME: 'STACK_RECORDED_UNDER_EARLIER_NAME',
|
|
160
|
+
PORT_FAMILY_COLLISION: 'PORT_FAMILY_COLLISION',
|
|
161
|
+
PORT_LISTENER_EVIDENCE_INVALID: 'PORT_LISTENER_EVIDENCE_INVALID',
|
|
162
|
+
PORT_FAMILY_OUT_OF_RANGE: 'PORT_FAMILY_OUT_OF_RANGE',
|
|
163
|
+
PORT_LEASE_EXHAUSTED: 'PORT_LEASE_EXHAUSTED',
|
|
164
|
+
PORT_LOCAL_VALUE_CORRECTED: 'PORT_LOCAL_VALUE_CORRECTED',
|
|
165
|
+
PORT_EXTERNAL_REGISTRATION_GAP: 'PORT_EXTERNAL_REGISTRATION_GAP',
|
|
166
|
+
CLAIM_CO_TENANT: 'CLAIM_CO_TENANT',
|
|
167
|
+
CLAIM_LIVENESS_UNKNOWN: 'CLAIM_LIVENESS_UNKNOWN',
|
|
168
|
+
DRAIN_ATTEMPT_REPAIR_REQUIRED: 'DRAIN_ATTEMPT_REPAIR_REQUIRED',
|
|
169
|
+
INSTALL_POLICY_OBSERVATION_UNAVAILABLE: 'INSTALL_POLICY_OBSERVATION_UNAVAILABLE',
|
|
170
|
+
INSTALL_POLICY_OBSERVATION_INVALID: 'INSTALL_POLICY_OBSERVATION_INVALID',
|
|
171
|
+
INSTALL_POLICY_MISSING: 'INSTALL_POLICY_MISSING',
|
|
172
|
+
INSTALL_POLICY_AMBIGUOUS: 'INSTALL_POLICY_AMBIGUOUS',
|
|
173
|
+
TEMPLATE_NOT_FOUND: 'TEMPLATE_NOT_FOUND',
|
|
174
|
+
TEMPLATE_NOT_TRACKED: 'TEMPLATE_NOT_TRACKED',
|
|
175
|
+
TEMPLATE_IGNORED: 'TEMPLATE_IGNORED',
|
|
176
|
+
TEMPLATE_PATH_OUTSIDE_ROOT: 'TEMPLATE_PATH_OUTSIDE_ROOT',
|
|
177
|
+
ENVIRONMENT_FILE_NOT_FOUND: 'ENVIRONMENT_FILE_NOT_FOUND',
|
|
178
|
+
ENVIRONMENT_FILE_UNREADABLE: 'ENVIRONMENT_FILE_UNREADABLE',
|
|
179
|
+
ENVIRONMENT_FILE_TOO_LARGE: 'ENVIRONMENT_FILE_TOO_LARGE',
|
|
180
|
+
ENVIRONMENT_FILE_MALFORMED: 'ENVIRONMENT_FILE_MALFORMED',
|
|
181
|
+
INSTANCE_NOT_IGNORED: 'INSTANCE_NOT_IGNORED',
|
|
182
|
+
ENVIRONMENT_SEED_PRECONDITION_CHANGED: 'ENVIRONMENT_SEED_PRECONDITION_CHANGED',
|
|
183
|
+
ENVIRONMENT_SEED_FAILED: 'ENVIRONMENT_SEED_FAILED',
|
|
184
|
+
RUNTIME_UNAVAILABLE: 'RUNTIME_UNAVAILABLE',
|
|
185
|
+
RUNTIME_IMAGE_UNAVAILABLE: 'RUNTIME_IMAGE_UNAVAILABLE',
|
|
186
|
+
RUNTIME_UNMEASURED: 'RUNTIME_UNMEASURED',
|
|
187
|
+
RUNTIME_COMPOSE_REMOTE: 'RUNTIME_COMPOSE_REMOTE',
|
|
188
|
+
RUNTIME_PROBE_TIMEOUT: 'RUNTIME_PROBE_TIMEOUT',
|
|
189
|
+
LOGS_TRUNCATED: 'LOGS_TRUNCATED',
|
|
190
|
+
RESET_CONFIRMATION_REQUIRED: 'RESET_CONFIRMATION_REQUIRED',
|
|
191
|
+
RESET_CONFIRMATION_MISMATCH: 'RESET_CONFIRMATION_MISMATCH',
|
|
192
|
+
RESET_CO_TENANT: 'RESET_CO_TENANT',
|
|
193
|
+
EVIDENCE_UNAVAILABLE: 'EVIDENCE_UNAVAILABLE',
|
|
194
|
+
RECLAIM_LABEL_ESCAPE: 'RECLAIM_LABEL_ESCAPE',
|
|
195
|
+
RECLAIM_ACCOUNTING_MISMATCH: 'RECLAIM_ACCOUNTING_MISMATCH',
|
|
196
|
+
DOWN_RESOURCES_KEPT: 'DOWN_RESOURCES_KEPT',
|
|
197
|
+
CONFIG_STALE: 'CONFIG_STALE',
|
|
198
|
+
SIBLING_MISSING: 'SIBLING_MISSING',
|
|
199
|
+
GUIDE_CAP_EXCEEDED: 'GUIDE_CAP_EXCEEDED',
|
|
200
|
+
SIBLING_GUIDE_MISSING: 'SIBLING_GUIDE_MISSING',
|
|
201
|
+
MACHINE_MEMORY_BELOW_FLOOR: 'MACHINE_MEMORY_BELOW_FLOOR',
|
|
202
|
+
MACHINE_CPU_BELOW_FLOOR: 'MACHINE_CPU_BELOW_FLOOR',
|
|
203
|
+
MACHINE_DISK_BELOW_FLOOR: 'MACHINE_DISK_BELOW_FLOOR',
|
|
204
|
+
MACHINE_COLD_START_EXCEEDED: 'MACHINE_COLD_START_EXCEEDED',
|
|
205
|
+
GIT_STATE_UNHEALTHY: 'GIT_STATE_UNHEALTHY',
|
|
206
|
+
CHECKOUT_ADJACENCY_UNHEALTHY: 'CHECKOUT_ADJACENCY_UNHEALTHY',
|
|
207
|
+
GIT_COMPARISON_REMOTE_MISMATCH: 'GIT_COMPARISON_REMOTE_MISMATCH',
|
|
208
|
+
RUNNING_CHECKOUT_MISMATCH: 'RUNNING_CHECKOUT_MISMATCH',
|
|
209
|
+
ENVIRONMENT_KEYS_STALE: 'ENVIRONMENT_KEYS_STALE',
|
|
210
|
+
ENV_SCHEMA_UNHEALTHY: 'ENV_SCHEMA_UNHEALTHY',
|
|
211
|
+
ENV_SCHEMA_TOOL_MISSING: 'ENV_SCHEMA_TOOL_MISSING',
|
|
212
|
+
GENERATED_ENVIRONMENT_UNAVAILABLE: 'GENERATED_ENVIRONMENT_UNAVAILABLE',
|
|
213
|
+
CLAIM_STATE_UNHEALTHY: 'CLAIM_STATE_UNHEALTHY',
|
|
214
|
+
MOUNT_POSTURE_UNAVAILABLE: 'MOUNT_POSTURE_UNAVAILABLE',
|
|
215
|
+
STATE_UNSEEDED: 'STATE_UNSEEDED',
|
|
216
|
+
STACK_NOT_RUNNING: 'STACK_NOT_RUNNING',
|
|
217
|
+
SKILL_BUDGET_UNAVAILABLE: 'SKILL_BUDGET_UNAVAILABLE',
|
|
218
|
+
HARNESS_SURFACE_UNAVAILABLE: 'HARNESS_SURFACE_UNAVAILABLE',
|
|
219
|
+
DIRECTORY_GRANTS_UNAVAILABLE: 'DIRECTORY_GRANTS_UNAVAILABLE',
|
|
220
|
+
TEAM_METADATA_UNAVAILABLE: 'TEAM_METADATA_UNAVAILABLE',
|
|
221
|
+
COCKPIT_VERSION_MISMATCH: 'COCKPIT_VERSION_MISMATCH',
|
|
222
|
+
MOUNT_MATERIALIZATION_UNAVAILABLE: 'MOUNT_MATERIALIZATION_UNAVAILABLE',
|
|
223
|
+
ENVIRONMENT_NOT_DECLARED: 'ENVIRONMENT_NOT_DECLARED',
|
|
224
|
+
SERVICE_NOT_DECLARED: 'SERVICE_NOT_DECLARED',
|
|
225
|
+
GUARD_HOSTS_UNDECLARED: 'GUARD_HOSTS_UNDECLARED',
|
|
226
|
+
TESTING_GATE_UNDECLARED: 'TESTING_GATE_UNDECLARED',
|
|
227
|
+
EVALUATOR_UNAVAILABLE: 'EVALUATOR_UNAVAILABLE',
|
|
228
|
+
EVALUATOR_RUN_FAILED: 'EVALUATOR_RUN_FAILED',
|
|
229
|
+
EVALUATOR_FELL_BACK_TO_RUNNING_TOOL: 'EVALUATOR_FELL_BACK_TO_RUNNING_TOOL',
|
|
230
|
+
EVALUATOR_ANSWER_INVALID: 'EVALUATOR_ANSWER_INVALID',
|
|
231
|
+
TEST_GATE_UNSATISFIED: 'TEST_GATE_UNSATISFIED',
|
|
232
|
+
WORK_GRADE_UNSATISFIED: 'WORK_GRADE_UNSATISFIED',
|
|
233
|
+
WORK_CHECK_FAILED: 'WORK_CHECK_FAILED',
|
|
234
|
+
WORK_VERIFY_FAILED: 'WORK_VERIFY_FAILED',
|
|
235
|
+
WORK_PERSON_REQUIRED: 'WORK_PERSON_REQUIRED',
|
|
236
|
+
AUTONOMY_PERSON_REQUIRED: 'AUTONOMY_PERSON_REQUIRED',
|
|
237
|
+
AUTONOMY_CI_ONLY: 'AUTONOMY_CI_ONLY',
|
|
238
|
+
POLICY_WEAKENING_UNCONFIRMED: 'POLICY_WEAKENING_UNCONFIRMED',
|
|
239
|
+
WORK_ORDER_CLOSED: 'WORK_ORDER_CLOSED',
|
|
240
|
+
CODEX_HOOK_UNTRUSTED: 'CODEX_HOOK_UNTRUSTED',
|
|
241
|
+
SELFTEST_CUSTOM_PROBE_UNSUPPORTED: 'SELFTEST_CUSTOM_PROBE_UNSUPPORTED',
|
|
242
|
+
DECLARATION_UNCONFIRMED: 'DECLARATION_UNCONFIRMED',
|
|
243
|
+
COCKPIT_NOT_INSTALLED: 'COCKPIT_NOT_INSTALLED',
|
|
244
|
+
COCKPIT_LAUNCHER_UNPROVEN: 'COCKPIT_LAUNCHER_UNPROVEN',
|
|
245
|
+
SIBLING_REMOTE_UNRECORDED: 'SIBLING_REMOTE_UNRECORDED',
|
|
246
|
+
SECRET_FILE_TRACKED: 'SECRET_FILE_TRACKED',
|
|
247
|
+
SIBLING_INSTRUCTIONS_AGENTS_ONLY: 'SIBLING_INSTRUCTIONS_AGENTS_ONLY',
|
|
248
|
+
SIBLING_INSTRUCTIONS_CLAUDE_ONLY: 'SIBLING_INSTRUCTIONS_CLAUDE_ONLY',
|
|
249
|
+
SIBLING_INSTRUCTIONS_UNLINKED: 'SIBLING_INSTRUCTIONS_UNLINKED',
|
|
250
|
+
SIBLING_INSTRUCTIONS_MISSING: 'SIBLING_INSTRUCTIONS_MISSING',
|
|
251
|
+
SIBLING_INSTRUCTIONS_TOOL_ONLY: 'SIBLING_INSTRUCTIONS_TOOL_ONLY',
|
|
252
|
+
GUARD_SEARCH_PATH_RELATIVE: 'GUARD_SEARCH_PATH_RELATIVE',
|
|
253
|
+
SESSION_STACK_RETAINED: 'SESSION_STACK_RETAINED',
|
|
254
|
+
UPGRADE_PACKAGE_MANAGER_UNKNOWN: 'UPGRADE_PACKAGE_MANAGER_UNKNOWN',
|
|
255
|
+
UPGRADE_REGISTRY_UNREACHABLE: 'UPGRADE_REGISTRY_UNREACHABLE',
|
|
256
|
+
UPGRADE_VERSION_INVALID: 'UPGRADE_VERSION_INVALID',
|
|
257
|
+
UPGRADE_ALREADY_CURRENT: 'UPGRADE_ALREADY_CURRENT',
|
|
258
|
+
UPGRADE_INSTALL_FAILED: 'UPGRADE_INSTALL_FAILED',
|
|
259
|
+
UPGRADE_SYNC_FAILED: 'UPGRADE_SYNC_FAILED',
|
|
260
|
+
DATA_SEED_FAILED: 'DATA_SEED_FAILED',
|
|
261
|
+
DATA_SEED_UNAVAILABLE: 'DATA_SEED_UNAVAILABLE',
|
|
262
|
+
});
|
|
263
|
+
export const EXECUTION_FAILURE_CODES = Object.freeze([
|
|
264
|
+
ENVIRONMENT_CODES.EXECUTION_SPAWN_FAILED,
|
|
265
|
+
ENVIRONMENT_CODES.EXECUTION_PRECONDITION_CHANGED,
|
|
266
|
+
ENVIRONMENT_CODES.EXECUTION_STAGING_FAILED,
|
|
267
|
+
ENVIRONMENT_CODES.EXECUTION_STAGING_CLEANUP_FAILED,
|
|
268
|
+
ENVIRONMENT_CODES.EXECUTION_TIMEOUT,
|
|
269
|
+
ENVIRONMENT_CODES.EXECUTION_STDOUT_LIMIT,
|
|
270
|
+
ENVIRONMENT_CODES.EXECUTION_STDERR_LIMIT,
|
|
271
|
+
ENVIRONMENT_CODES.EXECUTION_STEP_FAILED,
|
|
272
|
+
ENVIRONMENT_CODES.EXECUTION_ABORTED,
|
|
273
|
+
ENVIRONMENT_CODES.EXECUTION_TERMINATION_UNCONFIRMED,
|
|
274
|
+
]);
|
|
275
|
+
export const REFUSAL_CODES = Object.freeze([
|
|
276
|
+
ENVIRONMENT_CODES.CONFIG_NOT_FOUND,
|
|
277
|
+
ENVIRONMENT_CODES.CONFIG_UNREADABLE,
|
|
278
|
+
ENVIRONMENT_CODES.CONFIG_ENCODING_INVALID,
|
|
279
|
+
ENVIRONMENT_CODES.CONFIG_PARSE_INVALID,
|
|
280
|
+
ENVIRONMENT_CODES.CONFIG_SCHEMA_INVALID,
|
|
281
|
+
ENVIRONMENT_CODES.STATE_ROOT_UNAVAILABLE,
|
|
282
|
+
ENVIRONMENT_CODES.STATE_FORMAT_UNSUPPORTED,
|
|
283
|
+
ENVIRONMENT_CODES.STATE_RECORD_MALFORMED,
|
|
284
|
+
ENVIRONMENT_CODES.STATE_LOCKED,
|
|
285
|
+
ENVIRONMENT_CODES.STATE_DURABILITY_INDETERMINATE,
|
|
286
|
+
ENVIRONMENT_CODES.SETUP_CONFIG_REQUIRED,
|
|
287
|
+
ENVIRONMENT_CODES.SETUP_OPTION_DUPLICATE,
|
|
288
|
+
ENVIRONMENT_CODES.SETUP_POSITIONAL_UNSUPPORTED,
|
|
289
|
+
ENVIRONMENT_CODES.SETUP_PATH_OUTSIDE_ROOT,
|
|
290
|
+
ENVIRONMENT_CODES.SETUP_PATH_SYMLINK,
|
|
291
|
+
ENVIRONMENT_CODES.SETUP_PATH_TYPE_INVALID,
|
|
292
|
+
ENVIRONMENT_CODES.SETUP_PARENT_MISSING,
|
|
293
|
+
ENVIRONMENT_CODES.SETUP_REMOTE_MISMATCH,
|
|
294
|
+
ENVIRONMENT_CODES.SETUP_REMOTE_UNRESOLVABLE,
|
|
295
|
+
ENVIRONMENT_CODES.SETUP_MANUAL_MISSING,
|
|
296
|
+
ENVIRONMENT_CODES.SETUP_CLONE_FAILED,
|
|
297
|
+
ENVIRONMENT_CODES.SETUP_POSTCHECK_FAILED,
|
|
298
|
+
ENVIRONMENT_CODES.SETUP_INSTRUCTION_POINTER_INVALID,
|
|
299
|
+
ENVIRONMENT_CODES.SETUP_INSTRUCTION_FILES_INVALID,
|
|
300
|
+
ENVIRONMENT_CODES.CONFIG_CHANGED_DURING_EXECUTION,
|
|
301
|
+
...EXECUTION_FAILURE_CODES,
|
|
302
|
+
ENVIRONMENT_CODES.EXECUTION_COMPENSATION_TIMEOUT,
|
|
303
|
+
ENVIRONMENT_CODES.EXECUTION_COMPENSATION_STEP_FAILED,
|
|
304
|
+
ENVIRONMENT_CODES.LIFECYCLE_EVIDENCE_INVALID,
|
|
305
|
+
ENVIRONMENT_CODES.LIFECYCLE_PROGRESS_INVALID,
|
|
306
|
+
ENVIRONMENT_CODES.STACK_RECORDED_UNDER_EARLIER_NAME,
|
|
307
|
+
ENVIRONMENT_CODES.PORT_FAMILY_COLLISION,
|
|
308
|
+
ENVIRONMENT_CODES.PORT_LISTENER_EVIDENCE_INVALID,
|
|
309
|
+
ENVIRONMENT_CODES.PORT_FAMILY_OUT_OF_RANGE,
|
|
310
|
+
ENVIRONMENT_CODES.PORT_LEASE_EXHAUSTED,
|
|
311
|
+
ENVIRONMENT_CODES.CLAIM_CO_TENANT,
|
|
312
|
+
ENVIRONMENT_CODES.CLAIM_LIVENESS_UNKNOWN,
|
|
313
|
+
ENVIRONMENT_CODES.DRAIN_ATTEMPT_REPAIR_REQUIRED,
|
|
314
|
+
ENVIRONMENT_CODES.INSTALL_POLICY_OBSERVATION_UNAVAILABLE,
|
|
315
|
+
ENVIRONMENT_CODES.INSTALL_POLICY_OBSERVATION_INVALID,
|
|
316
|
+
ENVIRONMENT_CODES.INSTALL_POLICY_MISSING,
|
|
317
|
+
ENVIRONMENT_CODES.INSTALL_POLICY_AMBIGUOUS,
|
|
318
|
+
ENVIRONMENT_CODES.TEMPLATE_NOT_FOUND,
|
|
319
|
+
ENVIRONMENT_CODES.TEMPLATE_NOT_TRACKED,
|
|
320
|
+
ENVIRONMENT_CODES.TEMPLATE_IGNORED,
|
|
321
|
+
ENVIRONMENT_CODES.TEMPLATE_PATH_OUTSIDE_ROOT,
|
|
322
|
+
ENVIRONMENT_CODES.ENVIRONMENT_FILE_NOT_FOUND,
|
|
323
|
+
ENVIRONMENT_CODES.ENVIRONMENT_FILE_UNREADABLE,
|
|
324
|
+
ENVIRONMENT_CODES.ENVIRONMENT_FILE_TOO_LARGE,
|
|
325
|
+
ENVIRONMENT_CODES.ENVIRONMENT_FILE_MALFORMED,
|
|
326
|
+
ENVIRONMENT_CODES.INSTANCE_NOT_IGNORED,
|
|
327
|
+
ENVIRONMENT_CODES.ENVIRONMENT_SEED_PRECONDITION_CHANGED,
|
|
328
|
+
ENVIRONMENT_CODES.ENVIRONMENT_SEED_FAILED,
|
|
329
|
+
ENVIRONMENT_CODES.RUNTIME_UNAVAILABLE,
|
|
330
|
+
ENVIRONMENT_CODES.RUNTIME_IMAGE_UNAVAILABLE,
|
|
331
|
+
ENVIRONMENT_CODES.RUNTIME_UNMEASURED,
|
|
332
|
+
ENVIRONMENT_CODES.RUNTIME_COMPOSE_REMOTE,
|
|
333
|
+
ENVIRONMENT_CODES.RUNTIME_PROBE_TIMEOUT,
|
|
334
|
+
ENVIRONMENT_CODES.RESET_CONFIRMATION_REQUIRED,
|
|
335
|
+
ENVIRONMENT_CODES.RESET_CONFIRMATION_MISMATCH,
|
|
336
|
+
ENVIRONMENT_CODES.RESET_CO_TENANT,
|
|
337
|
+
ENVIRONMENT_CODES.EVIDENCE_UNAVAILABLE,
|
|
338
|
+
ENVIRONMENT_CODES.RECLAIM_LABEL_ESCAPE,
|
|
339
|
+
ENVIRONMENT_CODES.RECLAIM_ACCOUNTING_MISMATCH,
|
|
340
|
+
ENVIRONMENT_CODES.DOWN_RESOURCES_KEPT,
|
|
341
|
+
ENVIRONMENT_CODES.GIT_COMPARISON_REMOTE_MISMATCH,
|
|
342
|
+
]);
|
|
343
|
+
// A refusal cockpit itself words. Its message is cockpit-authored text (fixed wording, paths and
|
|
344
|
+
// identifiers, never parsed bytes or a child's output), so errorCause surfaces it.
|
|
345
|
+
export class RefusalError extends Error {
|
|
346
|
+
}
|
|
347
|
+
// A refusal names its cause in one bounded line. A RefusalError is cockpit's own wording, and a system
|
|
348
|
+
// error (errno code plus syscall) carries only the operation and the path, so their first line is
|
|
349
|
+
// surfaced. Any other message can echo the bytes being parsed or a child's output, environment-file
|
|
350
|
+
// values among them, so only its class is named. Only own data properties are read: a thrown value can
|
|
351
|
+
// be hostile, and describing it must not throw again. A RefusalError gets the wider bound because its
|
|
352
|
+
// wording often ends in the command that fixes it, which a cut would drop.
|
|
353
|
+
export function errorCause(error) {
|
|
354
|
+
if (isProxy(error) || !(error instanceof Error))
|
|
355
|
+
return 'a non-error value was thrown';
|
|
356
|
+
const own = (key) => Object.getOwnPropertyDescriptor(error, key)?.value;
|
|
357
|
+
const message = own('message');
|
|
358
|
+
if (typeof message === 'string') {
|
|
359
|
+
const line = message.split(/\r?\n|\r/, 1)[0];
|
|
360
|
+
if (error instanceof RefusalError)
|
|
361
|
+
return line.slice(0, OBSERVATION_REASON_BYTE_LIMIT);
|
|
362
|
+
if (typeof own('code') === 'string' && typeof own('syscall') === 'string')
|
|
363
|
+
return line.slice(0, 240);
|
|
364
|
+
}
|
|
365
|
+
return error instanceof TypeError ? 'TypeError' : error instanceof SyntaxError ? 'SyntaxError'
|
|
366
|
+
: error instanceof RangeError ? 'RangeError' : 'Error';
|
|
367
|
+
}
|
|
368
|
+
// A JSON.parse error quotes the bytes where parsing stopped, and a refusal reaches an agent that may
|
|
369
|
+
// not read that file; name the subject, where parsing stopped and the shape expected, never the bytes.
|
|
370
|
+
export function parseJsonText(text, subject, expected) {
|
|
371
|
+
try {
|
|
372
|
+
return { value: JSON.parse(text) };
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
if (!(error instanceof SyntaxError))
|
|
376
|
+
throw error;
|
|
377
|
+
const position = Number(/\bposition (\d+)\b/.exec(error.message)?.[1]);
|
|
378
|
+
const before = Number.isSafeInteger(position) ? text.slice(0, position) : undefined;
|
|
379
|
+
const where = before === undefined ? '' : ` at line ${before.split('\n').length}, column ${before.length - before.lastIndexOf('\n')}`;
|
|
380
|
+
return { refusal: `${subject} is not valid JSON${where}; expected ${expected}` };
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
// For callers that refuse malformed input in their own words: unparseable text is undefined, and the
|
|
384
|
+
// parser's message, which quotes the bytes, is never read.
|
|
385
|
+
export function tryParseJson(text) {
|
|
386
|
+
try {
|
|
387
|
+
return JSON.parse(text);
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
if (!(error instanceof SyntaxError))
|
|
391
|
+
throw error;
|
|
392
|
+
return undefined;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
export function hasErrorCode(error, ...codes) {
|
|
396
|
+
if (isProxy(error) || !(error instanceof Error))
|
|
397
|
+
return false;
|
|
398
|
+
const code = Object.getOwnPropertyDescriptor(error, 'code')?.value;
|
|
399
|
+
return typeof code === 'string' && codes.includes(code);
|
|
400
|
+
}
|
|
401
|
+
export function isMissing(error) {
|
|
402
|
+
return hasErrorCode(error, 'ENOENT', 'ENOTDIR');
|
|
403
|
+
}
|
|
404
|
+
const canonicalTimestamp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
405
|
+
export function isCanonicalTimestamp(value) {
|
|
406
|
+
if (typeof value !== 'string' || !canonicalTimestamp.test(value))
|
|
407
|
+
return false;
|
|
408
|
+
const milliseconds = Date.parse(value);
|
|
409
|
+
return Number.isFinite(milliseconds) && new Date(milliseconds).toISOString() === value;
|
|
410
|
+
}
|
|
411
|
+
// Device and inode alone do not name an object over time: ext4 hands the inode number a removal
|
|
412
|
+
// just freed to the next object created, so a path removed and recreated between planning and
|
|
413
|
+
// execution reproduces the recorded pair exactly. Birth time is fixed at creation, so it tells the
|
|
414
|
+
// replacement apart while still admitting the content changes a cache or its parent legitimately
|
|
415
|
+
// sees between planning and removal; change time would refuse those. A filesystem that records no
|
|
416
|
+
// birth time reports 0 for both objects, and the comparison falls back to device and inode, which
|
|
417
|
+
// leaves in-place recreation undetectable there.
|
|
418
|
+
export function filesystemObjectIdentity(status) {
|
|
419
|
+
return { dev: Number(status.dev), ino: Number(status.ino), birthtimeNs: String(status.birthtimeNs) };
|
|
420
|
+
}
|
|
421
|
+
export function sameFilesystemObject(status, recorded) {
|
|
422
|
+
return Number(status.dev) === recorded.dev && Number(status.ino) === recorded.ino
|
|
423
|
+
&& String(status.birthtimeNs) === recorded.birthtimeNs;
|
|
424
|
+
}
|
|
425
|
+
export function isFilesystemObjectIdentity(value) {
|
|
426
|
+
return Number.isSafeInteger(value.dev) && value.dev >= 0
|
|
427
|
+
&& Number.isSafeInteger(value.ino) && value.ino >= 0
|
|
428
|
+
&& typeof value.birthtimeNs === 'string' && /^(0|-?[1-9][0-9]{0,19})$/.test(value.birthtimeNs);
|
|
429
|
+
}
|
|
430
|
+
function stringTuple(value) {
|
|
431
|
+
return Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === 'string' && !item.includes('\0'));
|
|
432
|
+
}
|
|
433
|
+
function stringRecord(value) {
|
|
434
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
435
|
+
&& Object.entries(value).every(([name, item]) => name.length > 0 && !name.includes('\0') && !name.includes('=')
|
|
436
|
+
&& typeof item === 'string' && !item.includes('\0'));
|
|
437
|
+
}
|
|
438
|
+
function canonicalPaths(value) {
|
|
439
|
+
return Array.isArray(value) && new Set(value).size === value.length
|
|
440
|
+
&& value.every((path) => typeof path === 'string' && isAbsolute(path) && normalize(path) === path && !path.includes('\0'));
|
|
441
|
+
}
|
|
442
|
+
function filesystemChecks(value) {
|
|
443
|
+
return Array.isArray(value) && value.every((candidate) => {
|
|
444
|
+
if (candidate === null || typeof candidate !== 'object')
|
|
445
|
+
return false;
|
|
446
|
+
const check = candidate;
|
|
447
|
+
const identity = check.identity;
|
|
448
|
+
const identityIsValid = identity === undefined || identity !== null && typeof identity === 'object'
|
|
449
|
+
&& exactKeys(identity, ['dev', 'ino', 'birthtimeNs', 'ancestors'])
|
|
450
|
+
&& isFilesystemObjectIdentity(identity)
|
|
451
|
+
&& Array.isArray(identity.ancestors) && identity.ancestors.length >= 1 && identity.ancestors.length <= 64
|
|
452
|
+
&& new Set(identity.ancestors.map((ancestor) => ancestor?.path)).size === identity.ancestors.length
|
|
453
|
+
&& identity.ancestors.every((ancestor, index) => ancestor !== null && typeof ancestor === 'object'
|
|
454
|
+
&& exactKeys(ancestor, ['path', 'dev', 'ino', 'birthtimeNs']) && canonicalPaths([ancestor.path])
|
|
455
|
+
&& isFilesystemObjectIdentity(ancestor)
|
|
456
|
+
&& (index === 0 || dirname(ancestor.path) === identity.ancestors[index - 1].path))
|
|
457
|
+
&& typeof check.path === 'string' && dirname(check.path) === identity.ancestors.at(-1).path;
|
|
458
|
+
const keys = ['path', 'expected', ...(check.sha256 === undefined ? [] : ['sha256', 'maxBytes']), ...(identity === undefined ? [] : ['identity'])];
|
|
459
|
+
return exactKeys(candidate, keys)
|
|
460
|
+
&& canonicalPaths([check.path]) && (check.expected === 'absent' || check.expected === 'directory' || check.expected === 'file')
|
|
461
|
+
&& (check.sha256 === undefined
|
|
462
|
+
? check.maxBytes === undefined
|
|
463
|
+
: check.expected === 'file' && typeof check.sha256 === 'string' && /^[a-f0-9]{64}$/.test(check.sha256)
|
|
464
|
+
&& Number.isSafeInteger(check.maxBytes) && check.maxBytes >= 1 && check.maxBytes <= 536_870_912)
|
|
465
|
+
&& identityIsValid && (identity === undefined || check.expected !== 'absent');
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
function consumedFiles(value, argv) {
|
|
469
|
+
if (!Array.isArray(value))
|
|
470
|
+
return false;
|
|
471
|
+
const paths = new Set();
|
|
472
|
+
const indexes = new Set();
|
|
473
|
+
let executableCount = 0;
|
|
474
|
+
for (const candidate of value) {
|
|
475
|
+
if (candidate === null || typeof candidate !== 'object')
|
|
476
|
+
return false;
|
|
477
|
+
const file = candidate;
|
|
478
|
+
if (!exactKeys(candidate, file.executable
|
|
479
|
+
? ['path', 'sha256', 'maxBytes', 'argvIndexes', 'executable', 'executionMode']
|
|
480
|
+
: ['path', 'sha256', 'maxBytes', 'argvIndexes', 'executable']) || !canonicalPaths([file.path])
|
|
481
|
+
|| typeof file.sha256 !== 'string' || !/^[a-f0-9]{64}$/.test(file.sha256) || !Array.isArray(file.argvIndexes)
|
|
482
|
+
|| !Number.isSafeInteger(file.maxBytes) || file.maxBytes < 1 || file.maxBytes > 536_870_912
|
|
483
|
+
|| file.argvIndexes.length === 0 || typeof file.executable !== 'boolean' || paths.has(file.path)
|
|
484
|
+
|| (file.executable && file.executionMode !== 'verified-path'))
|
|
485
|
+
return false;
|
|
486
|
+
paths.add(file.path);
|
|
487
|
+
if (file.executable)
|
|
488
|
+
executableCount += 1;
|
|
489
|
+
for (const index of file.argvIndexes) {
|
|
490
|
+
if (!Number.isSafeInteger(index) || index < 0 || index >= argv.length || indexes.has(index)
|
|
491
|
+
|| argv[index] !== file.path || (index === 0) !== file.executable)
|
|
492
|
+
return false;
|
|
493
|
+
indexes.add(index);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return value.length === 0 || executableCount === 1;
|
|
497
|
+
}
|
|
498
|
+
function expectedObservations(value) {
|
|
499
|
+
return Array.isArray(value) && value.every((candidate) => {
|
|
500
|
+
if (candidate === null || typeof candidate !== 'object')
|
|
501
|
+
return false;
|
|
502
|
+
const expected = candidate;
|
|
503
|
+
if (expected.kind === 'path')
|
|
504
|
+
return exactKeys(candidate, ['kind', 'target', 'state']) && canonicalPaths([expected.target])
|
|
505
|
+
&& ['absent', 'directory', 'repository'].includes(expected.state);
|
|
506
|
+
return expected.kind === 'remote' && exactKeys(candidate, ['kind', 'target', 'name', 'url']) && canonicalPaths([expected.target])
|
|
507
|
+
&& typeof expected.name === 'string' && expected.name.length > 0 && !expected.name.includes('\0')
|
|
508
|
+
&& typeof expected.url === 'string' && expected.url.length > 0 && !expected.url.includes('\0');
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
// Product test stages declare up to two hours; every other owner bounds its steps far lower itself.
|
|
512
|
+
export const MAX_STEP_TIMEOUT_MS = 7_200_000;
|
|
513
|
+
function executionStepSnapshot(snapshot, traversal) {
|
|
514
|
+
if (snapshot === undefined || snapshot === null || typeof snapshot !== 'object' || Array.isArray(snapshot))
|
|
515
|
+
return undefined;
|
|
516
|
+
const item = snapshot;
|
|
517
|
+
const baseKeys = ['id', 'argv', 'argv0', 'cwd', 'env', 'timeoutMs', 'stdoutLimitBytes', 'stderrLimitBytes', 'paths', 'ports', 'labels', 'expected', 'consumedFiles', 'filesystemChecks', 'compensation'];
|
|
518
|
+
const optionalKeys = [item.spawnNotAfter === undefined ? undefined : 'spawnNotAfter', item.executionFence === undefined ? undefined : 'executionFence',
|
|
519
|
+
item.outputOverflow === undefined ? undefined : 'outputOverflow', item.failureOutput === undefined ? undefined : 'failureOutput']
|
|
520
|
+
.filter((key) => key !== undefined);
|
|
521
|
+
if (!exactKeys(snapshot, [...baseKeys, ...optionalKeys])
|
|
522
|
+
|| typeof item.id !== 'string' || item.id.length === 0 || item.id.includes('\0') || traversal.count >= 256
|
|
523
|
+
|| traversal.ids.has(item.id) || !stringTuple(item.argv) || typeof item.argv0 !== 'string' || item.argv0.length === 0 || item.argv0.includes('\0')
|
|
524
|
+
|| item.argv[0].length === 0 || !canonicalPaths([item.cwd]) || !stringRecord(item.env)
|
|
525
|
+
|| !Number.isSafeInteger(item.timeoutMs) || item.timeoutMs <= 0 || item.timeoutMs > MAX_STEP_TIMEOUT_MS
|
|
526
|
+
|| item.outputOverflow !== undefined && item.outputOverflow !== 'retain-tail'
|
|
527
|
+
|| item.failureOutput !== undefined && item.failureOutput !== 'stderr-tail'
|
|
528
|
+
|| item.spawnNotAfter !== undefined && (!isCanonicalTimestamp(item.spawnNotAfter) || !Number.isFinite(Date.parse(item.spawnNotAfter)))
|
|
529
|
+
|| !Number.isSafeInteger(item.stdoutLimitBytes) || item.stdoutLimitBytes < 0 || item.stdoutLimitBytes > 16_777_216
|
|
530
|
+
|| !Number.isSafeInteger(item.stderrLimitBytes) || item.stderrLimitBytes < 0 || item.stderrLimitBytes > 16_777_216 || !canonicalPaths(item.paths)
|
|
531
|
+
|| !Array.isArray(item.ports) || new Set(item.ports).size !== item.ports.length || item.ports.some((port) => !Number.isSafeInteger(port) || port < 1 || port > 65_535)
|
|
532
|
+
|| !stringRecord(item.labels) || !expectedObservations(item.expected) || !consumedFiles(item.consumedFiles, item.argv)
|
|
533
|
+
|| !filesystemChecks(item.filesystemChecks) || item.filesystemChecks.some((check) => item.consumedFiles.some((file) => file.path === check.path))
|
|
534
|
+
|| item.executionFence !== undefined && (!exactKeys(item.executionFence, ['attemptId', 'markerPath', 'socketPath'])
|
|
535
|
+
|| typeof item.executionFence.attemptId !== 'string' || !/^[a-f0-9]{64}$/.test(item.executionFence.attemptId)
|
|
536
|
+
|| !canonicalPaths([item.executionFence.markerPath, item.executionFence.socketPath])
|
|
537
|
+
|| item.executionFence.markerPath === item.executionFence.socketPath || Buffer.byteLength(item.executionFence.socketPath) > 103)
|
|
538
|
+
|| !Array.isArray(item.compensation) || item.argv.length > 1_024 || Object.keys(item.env).length > 1_024 || Object.keys(item.labels).length > 1_024
|
|
539
|
+
|| item.paths.length > 1_024 || item.ports.length > 1_024 || item.expected.length > 1_024
|
|
540
|
+
|| item.consumedFiles.length > 1_024 || item.filesystemChecks.length > 1_024 || item.compensation.length > 1_024)
|
|
541
|
+
return undefined;
|
|
542
|
+
traversal.count += 1;
|
|
543
|
+
traversal.ids.add(item.id);
|
|
544
|
+
if (item.compensation.some((step) => executionStepSnapshot(step, traversal) === undefined))
|
|
545
|
+
return undefined;
|
|
546
|
+
return item;
|
|
547
|
+
}
|
|
548
|
+
export function snapshotExecutionStep(value) {
|
|
549
|
+
return executionStepSnapshot(snapshotJson(value), { count: 0, ids: new Set() });
|
|
550
|
+
}
|
|
551
|
+
export function snapshotExecutionPlan(value) {
|
|
552
|
+
const snapshot = snapshotJson(value);
|
|
553
|
+
if (snapshot === undefined || snapshot === null || typeof snapshot !== 'object' || Array.isArray(snapshot) || !exactKeys(snapshot, ['steps']))
|
|
554
|
+
return undefined;
|
|
555
|
+
const plan = snapshot;
|
|
556
|
+
const traversal = { count: 0, ids: new Set() };
|
|
557
|
+
return Array.isArray(plan.steps) && plan.steps.length <= 256
|
|
558
|
+
&& plan.steps.every((step) => executionStepSnapshot(step, traversal) !== undefined) ? plan : undefined;
|
|
559
|
+
}
|
|
560
|
+
export function snapshotLifecyclePlan(value) {
|
|
561
|
+
const snapshot = snapshotJsonWithEntryLimit(value, 16_384);
|
|
562
|
+
if (snapshot === undefined || snapshot === null || typeof snapshot !== 'object' || Array.isArray(snapshot)
|
|
563
|
+
|| !exactKeys(snapshot, ['verb', 'progress', 'steps', 'resumeBoundary', 'compensation', 'diagnostics']))
|
|
564
|
+
return undefined;
|
|
565
|
+
const plan = snapshot;
|
|
566
|
+
if (!['up', 'sleep', 'down', 'reset'].includes(plan.verb))
|
|
567
|
+
return undefined;
|
|
568
|
+
const progress = plan.progress;
|
|
569
|
+
if (progress === null || typeof progress !== 'object' || Array.isArray(progress)
|
|
570
|
+
|| !exactKeys(progress, ['workBasisSha256', 'operationGeneration', 'completedServices'])
|
|
571
|
+
|| typeof progress.workBasisSha256 !== 'string' || !/^[a-f0-9]{64}$/.test(progress.workBasisSha256)
|
|
572
|
+
|| typeof progress.operationGeneration !== 'string' || !/^[a-f0-9]{64}$/.test(progress.operationGeneration)
|
|
573
|
+
|| !Array.isArray(progress.completedServices) || progress.completedServices.length > 4_096)
|
|
574
|
+
return undefined;
|
|
575
|
+
const completedServices = new Set();
|
|
576
|
+
for (const completed of progress.completedServices) {
|
|
577
|
+
if (completed === null || typeof completed !== 'object' || Array.isArray(completed)
|
|
578
|
+
|| !exactKeys(completed, ['service', 'containerId'])
|
|
579
|
+
|| typeof completed.service !== 'string' || !/^[a-z0-9][a-z0-9_.-]*$/.test(completed.service)
|
|
580
|
+
|| typeof completed.containerId !== 'string' || !/^[a-f0-9]{64}$/.test(completed.containerId)
|
|
581
|
+
|| completedServices.has(completed.service))
|
|
582
|
+
return undefined;
|
|
583
|
+
completedServices.add(completed.service);
|
|
584
|
+
}
|
|
585
|
+
const stepIds = new Set();
|
|
586
|
+
const plannedServices = new Set();
|
|
587
|
+
const entrypointNames = new Set();
|
|
588
|
+
const captureStep = (candidate) => {
|
|
589
|
+
if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate))
|
|
590
|
+
return false;
|
|
591
|
+
const step = candidate;
|
|
592
|
+
if (typeof step.id !== 'string' || step.id.length === 0 || Buffer.byteLength(step.id) > 512 || step.id.includes('\0')
|
|
593
|
+
|| typeof step.kind !== 'string' || stepIds.has(step.id))
|
|
594
|
+
return false;
|
|
595
|
+
let valid = false;
|
|
596
|
+
if (step.kind === 'preflight') {
|
|
597
|
+
valid = exactKeys(candidate, ['id', 'kind']);
|
|
598
|
+
}
|
|
599
|
+
else if (step.kind === 'claim') {
|
|
600
|
+
valid = exactKeys(candidate, ['id', 'kind', 'action']) && (step.action === 'acquire' || step.action === 'release');
|
|
601
|
+
}
|
|
602
|
+
else if (step.kind === 'prepare') {
|
|
603
|
+
valid = exactKeys(candidate, ['id', 'kind', 'execution']) && snapshotExecutionStep(step.execution) !== undefined;
|
|
604
|
+
}
|
|
605
|
+
else if (step.kind === 'service') {
|
|
606
|
+
const service = step.service;
|
|
607
|
+
if (typeof service !== 'string')
|
|
608
|
+
return false;
|
|
609
|
+
valid = exactKeys(candidate, ['id', 'kind', 'service'])
|
|
610
|
+
&& /^[a-z0-9][a-z0-9_.-]*$/.test(service)
|
|
611
|
+
&& plannedServices.size < 4_096 && !plannedServices.has(service);
|
|
612
|
+
if (valid)
|
|
613
|
+
plannedServices.add(service);
|
|
614
|
+
}
|
|
615
|
+
else if (step.kind === 'publish-entrypoints') {
|
|
616
|
+
if (!exactKeys(candidate, ['id', 'kind', 'values']) || !Array.isArray(step.values) || step.values.length > 4_096)
|
|
617
|
+
return false;
|
|
618
|
+
valid = step.values.every((entrypoint) => {
|
|
619
|
+
if (entrypoint === null || typeof entrypoint !== 'object' || Array.isArray(entrypoint)
|
|
620
|
+
|| !exactKeys(entrypoint, ['name', 'kind', 'port', 'value']))
|
|
621
|
+
return false;
|
|
622
|
+
const value = entrypoint;
|
|
623
|
+
if (typeof value.name !== 'string' || !/^[a-z0-9][a-z0-9-]*$/.test(value.name)
|
|
624
|
+
|| entrypointNames.has(value.name) || !isEntrypointKind(value.kind)
|
|
625
|
+
|| typeof value.port !== 'string' || !/^[A-Z][A-Z0-9_]*$/.test(value.port)
|
|
626
|
+
|| !boundedContractText(value.value, 4_096))
|
|
627
|
+
return false;
|
|
628
|
+
entrypointNames.add(value.name);
|
|
629
|
+
return true;
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
if (!valid)
|
|
633
|
+
return false;
|
|
634
|
+
stepIds.add(step.id);
|
|
635
|
+
return true;
|
|
636
|
+
};
|
|
637
|
+
const captureSteps = (steps) => {
|
|
638
|
+
if (!Array.isArray(steps) || steps.length > 16_384)
|
|
639
|
+
return false;
|
|
640
|
+
return steps.every(captureStep);
|
|
641
|
+
};
|
|
642
|
+
if (!captureSteps(plan.steps) || !Array.isArray(plan.compensation) || plan.compensation.length > 256
|
|
643
|
+
|| !plan.compensation.every((candidate) => {
|
|
644
|
+
if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate)
|
|
645
|
+
|| !exactKeys(candidate, ['step', 'ownership']))
|
|
646
|
+
return false;
|
|
647
|
+
const item = candidate;
|
|
648
|
+
const ownership = item.ownership;
|
|
649
|
+
return captureStep(item.step) && item.step.kind === 'claim' && item.step.action === 'release'
|
|
650
|
+
&& ownership !== null && typeof ownership === 'object'
|
|
651
|
+
&& !Array.isArray(ownership) && exactKeys(ownership, ['stackId', 'holderId', 'recordRevision', 'change'])
|
|
652
|
+
&& typeof ownership.stackId === 'string' && /^stack:[a-f0-9]{64}$/.test(ownership.stackId)
|
|
653
|
+
&& typeof ownership.holderId === 'string' && /^holder:[a-f0-9]{64}:session$/.test(ownership.holderId)
|
|
654
|
+
&& Number.isSafeInteger(ownership.recordRevision) && ownership.recordRevision >= 0 && ownership.change === 'acquired';
|
|
655
|
+
}))
|
|
656
|
+
return undefined;
|
|
657
|
+
const boundary = plan.resumeBoundary;
|
|
658
|
+
if (boundary === null || typeof boundary !== 'object' || Array.isArray(boundary)
|
|
659
|
+
|| !exactKeys(boundary, ['completedStepIds', 'nextStepId']) || !Array.isArray(boundary.completedStepIds)
|
|
660
|
+
|| boundary.completedStepIds.length > 16_384 || new Set(boundary.completedStepIds).size !== boundary.completedStepIds.length
|
|
661
|
+
|| boundary.completedStepIds.some((id) => typeof id !== 'string' || id.length === 0 || Buffer.byteLength(id) > 512 || !stepIds.has(id))
|
|
662
|
+
|| boundary.nextStepId !== null && (typeof boundary.nextStepId !== 'string' || boundary.nextStepId.length === 0 || Buffer.byteLength(boundary.nextStepId) > 512 || !stepIds.has(boundary.nextStepId))
|
|
663
|
+
|| boundary.completedStepIds.some((id, index) => plan.steps[index]?.id !== id)
|
|
664
|
+
|| boundary.nextStepId !== (plan.steps[boundary.completedStepIds.length]?.id ?? null)
|
|
665
|
+
|| !Array.isArray(plan.diagnostics) || plan.diagnostics.length > 256
|
|
666
|
+
|| !plan.diagnostics.every((candidate) => {
|
|
667
|
+
if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate))
|
|
668
|
+
return false;
|
|
669
|
+
const item = candidate;
|
|
670
|
+
const keys = ['severity', 'code', 'message', ...(item.target === undefined ? [] : ['target']), ...(item.fix === undefined ? [] : ['fix'])];
|
|
671
|
+
return exactKeys(candidate, keys) && ['error', 'warning', 'info'].includes(item.severity)
|
|
672
|
+
&& Object.values(ENVIRONMENT_CODES).includes(item.code) && boundedContractText(item.message, 4_096)
|
|
673
|
+
&& (item.target === undefined || boundedContractText(item.target, 4_096))
|
|
674
|
+
&& (item.fix === undefined || boundedContractText(item.fix, 4_096));
|
|
675
|
+
}))
|
|
676
|
+
return undefined;
|
|
677
|
+
const completedPlanServices = plan.steps.slice(0, boundary.completedStepIds.length)
|
|
678
|
+
.filter((step) => step.kind === 'service');
|
|
679
|
+
if (progress.completedServices.length !== completedPlanServices.length
|
|
680
|
+
|| progress.completedServices.some((completed, index) => completed.service !== completedPlanServices[index]?.service))
|
|
681
|
+
return undefined;
|
|
682
|
+
return plan;
|
|
683
|
+
}
|
|
684
|
+
function boundedContractText(value, maximum = OBSERVATION_REASON_BYTE_LIMIT) {
|
|
685
|
+
return typeof value === 'string' && value.length > 0 && !value.includes('\0')
|
|
686
|
+
&& Buffer.byteLength(value, 'utf8') <= maximum;
|
|
687
|
+
}
|
|
688
|
+
function validExpectation(value) {
|
|
689
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
690
|
+
return false;
|
|
691
|
+
const candidate = value;
|
|
692
|
+
if (candidate.kind === 'present')
|
|
693
|
+
return exactKeys(value, ['kind']);
|
|
694
|
+
if (candidate.kind === 'one-of') {
|
|
695
|
+
return exactKeys(value, ['kind', 'values']) && Array.isArray(candidate.values)
|
|
696
|
+
&& candidate.values.length > 0 && candidate.values.length <= 4_096
|
|
697
|
+
&& candidate.values.every((item) => snapshotJson(item) !== undefined);
|
|
698
|
+
}
|
|
699
|
+
if (candidate.kind === 'minimum' || candidate.kind === 'maximum') {
|
|
700
|
+
return exactKeys(value, ['kind', 'value']) && Number.isSafeInteger(candidate.value);
|
|
701
|
+
}
|
|
702
|
+
return candidate.kind === 'equal' && exactKeys(value, ['kind', 'value'])
|
|
703
|
+
&& snapshotJson(candidate.value) !== undefined;
|
|
704
|
+
}
|
|
705
|
+
export function snapshotEnvironmentObservation(value) {
|
|
706
|
+
const snapshot = snapshotJson(value);
|
|
707
|
+
if (snapshot === undefined || snapshot === null || typeof snapshot !== 'object' || Array.isArray(snapshot)
|
|
708
|
+
|| !exactKeys(snapshot, ['code', 'owner', 'stackId', 'source', 'observed', 'expectation', 'applicability', 'freshness', 'remedy']))
|
|
709
|
+
return undefined;
|
|
710
|
+
const candidate = snapshot;
|
|
711
|
+
if (!Object.values(ENVIRONMENT_CODES).includes(candidate.code) || !boundedContractText(candidate.owner, OBSERVATION_PRODUCER_BYTE_LIMIT)
|
|
712
|
+
|| !/^stack:[a-f0-9]{64}$/.test(candidate.stackId) || !boundedContractText(candidate.source)
|
|
713
|
+
|| !boundedContractText(candidate.remedy) || !validExpectation(candidate.expectation))
|
|
714
|
+
return undefined;
|
|
715
|
+
const observed = candidate.observed;
|
|
716
|
+
if (observed === null || typeof observed !== 'object' || Array.isArray(observed)
|
|
717
|
+
|| !isCanonicalTimestamp(observed.observedAt))
|
|
718
|
+
return undefined;
|
|
719
|
+
if (observed.state === 'available') {
|
|
720
|
+
if (!exactKeys(observed, ['state', 'value', 'observedAt']) || snapshotJson(observed.value) === undefined)
|
|
721
|
+
return undefined;
|
|
722
|
+
}
|
|
723
|
+
else if ((observed.state === 'unavailable' || observed.state === 'failed')) {
|
|
724
|
+
if (!exactKeys(observed, ['state', 'reason', 'observedAt']) || !boundedContractText(observed.reason))
|
|
725
|
+
return undefined;
|
|
726
|
+
}
|
|
727
|
+
else
|
|
728
|
+
return undefined;
|
|
729
|
+
const applicability = candidate.applicability;
|
|
730
|
+
if (applicability === null || typeof applicability !== 'object' || Array.isArray(applicability)
|
|
731
|
+
|| !boundedContractText(applicability.posture, OBSERVATION_PRODUCER_BYTE_LIMIT))
|
|
732
|
+
return undefined;
|
|
733
|
+
if (applicability.state === 'required') {
|
|
734
|
+
if (!exactKeys(applicability, ['state', 'posture']))
|
|
735
|
+
return undefined;
|
|
736
|
+
}
|
|
737
|
+
else if (applicability.state === 'not-applicable') {
|
|
738
|
+
if (!exactKeys(applicability, ['state', 'posture', 'reason']) || !boundedContractText(applicability.reason))
|
|
739
|
+
return undefined;
|
|
740
|
+
}
|
|
741
|
+
else
|
|
742
|
+
return undefined;
|
|
743
|
+
const freshness = candidate.freshness;
|
|
744
|
+
if (freshness === null || typeof freshness !== 'object' || Array.isArray(freshness))
|
|
745
|
+
return undefined;
|
|
746
|
+
if (freshness.state === 'current') {
|
|
747
|
+
if (!exactKeys(freshness, ['state']))
|
|
748
|
+
return undefined;
|
|
749
|
+
}
|
|
750
|
+
else if (freshness.state === 'stale' || freshness.state === 'missing') {
|
|
751
|
+
if (!exactKeys(freshness, ['state', 'reason']) || !boundedContractText(freshness.reason))
|
|
752
|
+
return undefined;
|
|
753
|
+
}
|
|
754
|
+
else
|
|
755
|
+
return undefined;
|
|
756
|
+
return snapshot;
|
|
757
|
+
}
|
|
758
|
+
/** A command refusal carrying the diagnostics an owner raised: exit status 2 and no result. */
|
|
759
|
+
export function forwardedRefusal(diagnostics) {
|
|
760
|
+
return { kind: 'refusal', status: 2, result: null, diagnostics };
|
|
761
|
+
}
|