@intutic/cli 1.10.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/cli.js +868 -30
- package/dist/cli.js.map +1 -1
- package/dist/commands/attenuate.d.ts +39 -0
- package/dist/commands/attenuate.d.ts.map +1 -0
- package/dist/commands/attenuate.js +98 -0
- package/dist/commands/attenuate.js.map +1 -0
- package/dist/commands/budget.d.ts +80 -0
- package/dist/commands/budget.d.ts.map +1 -1
- package/dist/commands/budget.js +119 -3
- package/dist/commands/budget.js.map +1 -1
- package/dist/commands/connect.d.ts +10 -0
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +358 -48
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/credentials.d.ts +31 -0
- package/dist/commands/credentials.d.ts.map +1 -0
- package/dist/commands/credentials.js +134 -0
- package/dist/commands/credentials.js.map +1 -0
- package/dist/commands/decision.d.ts +37 -0
- package/dist/commands/decision.d.ts.map +1 -0
- package/dist/commands/decision.js +56 -0
- package/dist/commands/decision.js.map +1 -0
- package/dist/commands/doctor.d.ts +38 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +228 -18
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/enforce.d.ts +33 -0
- package/dist/commands/enforce.d.ts.map +1 -0
- package/dist/commands/enforce.js +150 -0
- package/dist/commands/enforce.js.map +1 -0
- package/dist/commands/enterprise.d.ts +29 -0
- package/dist/commands/enterprise.d.ts.map +1 -0
- package/dist/commands/enterprise.js +141 -0
- package/dist/commands/enterprise.js.map +1 -0
- package/dist/commands/env.d.ts +7 -0
- package/dist/commands/env.d.ts.map +1 -0
- package/dist/commands/env.js +55 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/exec.d.ts +38 -2
- package/dist/commands/exec.d.ts.map +1 -1
- package/dist/commands/exec.js +247 -10
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/findings.d.ts +84 -0
- package/dist/commands/findings.d.ts.map +1 -0
- package/dist/commands/findings.js +329 -0
- package/dist/commands/findings.js.map +1 -0
- package/dist/commands/gateway.d.ts +62 -0
- package/dist/commands/gateway.d.ts.map +1 -0
- package/dist/commands/gateway.js +298 -0
- package/dist/commands/gateway.js.map +1 -0
- package/dist/commands/guardrails.d.ts +81 -0
- package/dist/commands/guardrails.d.ts.map +1 -0
- package/dist/commands/guardrails.js +735 -0
- package/dist/commands/guardrails.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +14 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install-daemon.d.ts +70 -3
- package/dist/commands/install-daemon.d.ts.map +1 -1
- package/dist/commands/install-daemon.js +482 -47
- package/dist/commands/install-daemon.js.map +1 -1
- package/dist/commands/integrity.d.ts +205 -0
- package/dist/commands/integrity.d.ts.map +1 -0
- package/dist/commands/integrity.js +620 -0
- package/dist/commands/integrity.js.map +1 -0
- package/dist/commands/judge.d.ts +31 -0
- package/dist/commands/judge.d.ts.map +1 -0
- package/dist/commands/judge.js +118 -0
- package/dist/commands/judge.js.map +1 -0
- package/dist/commands/org.d.ts +31 -0
- package/dist/commands/org.d.ts.map +1 -0
- package/dist/commands/org.js +159 -0
- package/dist/commands/org.js.map +1 -0
- package/dist/commands/policy.d.ts +138 -4
- package/dist/commands/policy.d.ts.map +1 -1
- package/dist/commands/policy.js +538 -97
- package/dist/commands/policy.js.map +1 -1
- package/dist/commands/predict-cost.d.ts +45 -0
- package/dist/commands/predict-cost.d.ts.map +1 -0
- package/dist/commands/predict-cost.js +123 -0
- package/dist/commands/predict-cost.js.map +1 -0
- package/dist/commands/rollback.d.ts +5 -0
- package/dist/commands/rollback.d.ts.map +1 -0
- package/dist/commands/rollback.js +142 -0
- package/dist/commands/rollback.js.map +1 -0
- package/dist/commands/routing.d.ts +62 -0
- package/dist/commands/routing.d.ts.map +1 -0
- package/dist/commands/routing.js +121 -0
- package/dist/commands/routing.js.map +1 -0
- package/dist/commands/setup.d.ts +62 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +238 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/skill.d.ts +268 -1
- package/dist/commands/skill.d.ts.map +1 -1
- package/dist/commands/skill.js +744 -39
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/sops.d.ts +95 -0
- package/dist/commands/sops.d.ts.map +1 -1
- package/dist/commands/sops.js +334 -34
- package/dist/commands/sops.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +1 -18
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +44 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/team.d.ts +38 -0
- package/dist/commands/team.d.ts.map +1 -0
- package/dist/commands/team.js +140 -0
- package/dist/commands/team.js.map +1 -0
- package/dist/commands/traces.d.ts +8 -1
- package/dist/commands/traces.d.ts.map +1 -1
- package/dist/commands/traces.js +114 -15
- package/dist/commands/traces.js.map +1 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +2 -1
- package/dist/commands/whoami.js.map +1 -1
- package/dist/config/keychain.d.ts +10 -2
- package/dist/config/keychain.d.ts.map +1 -1
- package/dist/config/keychain.js +83 -14
- package/dist/config/keychain.js.map +1 -1
- package/dist/config/paths.d.ts +27 -0
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +37 -6
- package/dist/config/paths.js.map +1 -1
- package/dist/config/store.d.ts.map +1 -1
- package/dist/config/store.js +19 -3
- package/dist/config/store.js.map +1 -1
- package/dist/harness/ag2.d.ts +22 -0
- package/dist/harness/ag2.d.ts.map +1 -0
- package/dist/harness/ag2.js +34 -0
- package/dist/harness/ag2.js.map +1 -0
- package/dist/harness/agentcore.d.ts +55 -0
- package/dist/harness/agentcore.d.ts.map +1 -0
- package/dist/harness/agentcore.js +119 -0
- package/dist/harness/agentcore.js.map +1 -0
- package/dist/harness/agenticOrchestrator.d.ts +52 -0
- package/dist/harness/agenticOrchestrator.d.ts.map +1 -0
- package/dist/harness/agenticOrchestrator.js +115 -0
- package/dist/harness/agenticOrchestrator.js.map +1 -0
- package/dist/harness/aiSdkHarness.d.ts +30 -0
- package/dist/harness/aiSdkHarness.d.ts.map +1 -0
- package/dist/harness/aiSdkHarness.js +51 -0
- package/dist/harness/aiSdkHarness.js.map +1 -0
- package/dist/harness/aiSdkWorkflow.d.ts +26 -0
- package/dist/harness/aiSdkWorkflow.d.ts.map +1 -0
- package/dist/harness/aiSdkWorkflow.js +39 -0
- package/dist/harness/aiSdkWorkflow.js.map +1 -0
- package/dist/harness/autogen.d.ts +24 -0
- package/dist/harness/autogen.d.ts.map +1 -0
- package/dist/harness/autogen.js +36 -0
- package/dist/harness/autogen.js.map +1 -0
- package/dist/harness/base.js.map +1 -1
- package/dist/harness/continue.d.ts.map +1 -1
- package/dist/harness/continue.js +2 -1
- package/dist/harness/continue.js.map +1 -1
- package/dist/harness/crewai.d.ts +15 -0
- package/dist/harness/crewai.d.ts.map +1 -0
- package/dist/harness/crewai.js +26 -0
- package/dist/harness/crewai.js.map +1 -0
- package/dist/harness/detector.d.ts +1 -1
- package/dist/harness/detector.d.ts.map +1 -1
- package/dist/harness/detector.js +47 -1
- package/dist/harness/detector.js.map +1 -1
- package/dist/harness/dsh.d.ts +19 -0
- package/dist/harness/dsh.d.ts.map +1 -0
- package/dist/harness/dsh.js +93 -0
- package/dist/harness/dsh.js.map +1 -0
- package/dist/harness/eve.d.ts +40 -0
- package/dist/harness/eve.d.ts.map +1 -0
- package/dist/harness/eve.js +67 -0
- package/dist/harness/eve.js.map +1 -0
- package/dist/harness/googleAdk.d.ts +18 -0
- package/dist/harness/googleAdk.d.ts.map +1 -0
- package/dist/harness/googleAdk.js +29 -0
- package/dist/harness/googleAdk.js.map +1 -0
- package/dist/harness/goose.d.ts.map +1 -1
- package/dist/harness/goose.js +5 -1
- package/dist/harness/goose.js.map +1 -1
- package/dist/harness/grok.d.ts +16 -0
- package/dist/harness/grok.d.ts.map +1 -0
- package/dist/harness/grok.js +78 -0
- package/dist/harness/grok.js.map +1 -0
- package/dist/harness/jsSdkGatedAdapter.d.ts +102 -0
- package/dist/harness/jsSdkGatedAdapter.d.ts.map +1 -0
- package/dist/harness/jsSdkGatedAdapter.js +139 -0
- package/dist/harness/jsSdkGatedAdapter.js.map +1 -0
- package/dist/harness/langchain.d.ts +22 -0
- package/dist/harness/langchain.d.ts.map +1 -0
- package/dist/harness/langchain.js +33 -0
- package/dist/harness/langchain.js.map +1 -0
- package/dist/harness/langgraph.d.ts +22 -0
- package/dist/harness/langgraph.d.ts.map +1 -0
- package/dist/harness/langgraph.js +80 -0
- package/dist/harness/langgraph.js.map +1 -0
- package/dist/harness/mastra.d.ts +21 -0
- package/dist/harness/mastra.d.ts.map +1 -0
- package/dist/harness/mastra.js +33 -0
- package/dist/harness/mastra.js.map +1 -0
- package/dist/harness/muse.d.ts +22 -0
- package/dist/harness/muse.d.ts.map +1 -0
- package/dist/harness/muse.js +92 -0
- package/dist/harness/muse.js.map +1 -0
- package/dist/harness/n8n.d.ts.map +1 -1
- package/dist/harness/n8n.js +36 -11
- package/dist/harness/n8n.js.map +1 -1
- package/dist/harness/openaiAgents.d.ts +40 -0
- package/dist/harness/openaiAgents.d.ts.map +1 -0
- package/dist/harness/openaiAgents.js +107 -0
- package/dist/harness/openaiAgents.js.map +1 -0
- package/dist/harness/opencode.d.ts +24 -0
- package/dist/harness/opencode.d.ts.map +1 -0
- package/dist/harness/opencode.js +97 -0
- package/dist/harness/opencode.js.map +1 -0
- package/dist/harness/pydanticAi.d.ts +19 -0
- package/dist/harness/pydanticAi.d.ts.map +1 -0
- package/dist/harness/pydanticAi.js +30 -0
- package/dist/harness/pydanticAi.js.map +1 -0
- package/dist/harness/sdkGatedAdapter.d.ts +55 -0
- package/dist/harness/sdkGatedAdapter.d.ts.map +1 -0
- package/dist/harness/sdkGatedAdapter.js +85 -0
- package/dist/harness/sdkGatedAdapter.js.map +1 -0
- package/dist/harness/smolagents.d.ts +22 -0
- package/dist/harness/smolagents.d.ts.map +1 -0
- package/dist/harness/smolagents.js +33 -0
- package/dist/harness/smolagents.js.map +1 -0
- package/dist/harness/strands.d.ts +22 -0
- package/dist/harness/strands.d.ts.map +1 -0
- package/dist/harness/strands.js +35 -0
- package/dist/harness/strands.js.map +1 -0
- package/dist/harness/trueforge.d.ts +25 -0
- package/dist/harness/trueforge.d.ts.map +1 -0
- package/dist/harness/trueforge.js +40 -0
- package/dist/harness/trueforge.js.map +1 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js +70 -0
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/vercelAiSdk.d.ts +31 -0
- package/dist/harness/vercelAiSdk.d.ts.map +1 -0
- package/dist/harness/vercelAiSdk.js +44 -0
- package/dist/harness/vercelAiSdk.js.map +1 -0
- package/dist/harness/xirp.d.ts +43 -0
- package/dist/harness/xirp.d.ts.map +1 -0
- package/dist/harness/xirp.js +95 -0
- package/dist/harness/xirp.js.map +1 -0
- package/dist/lib/api.d.ts +68 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +108 -67
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/authMessages.d.ts +19 -0
- package/dist/lib/authMessages.d.ts.map +1 -0
- package/dist/lib/authMessages.js +20 -0
- package/dist/lib/authMessages.js.map +1 -0
- package/dist/lib/binaryChecksum.d.ts +12 -0
- package/dist/lib/binaryChecksum.d.ts.map +1 -0
- package/dist/lib/binaryChecksum.js +45 -0
- package/dist/lib/binaryChecksum.js.map +1 -0
- package/dist/lib/binaryOnPath.d.ts +24 -0
- package/dist/lib/binaryOnPath.d.ts.map +1 -0
- package/dist/lib/binaryOnPath.js +31 -0
- package/dist/lib/binaryOnPath.js.map +1 -0
- package/dist/lib/caTrust.d.ts +69 -0
- package/dist/lib/caTrust.d.ts.map +1 -0
- package/dist/lib/caTrust.js +169 -0
- package/dist/lib/caTrust.js.map +1 -0
- package/dist/lib/ciscoScanner.d.ts +178 -0
- package/dist/lib/ciscoScanner.d.ts.map +1 -0
- package/dist/lib/ciscoScanner.js +292 -0
- package/dist/lib/ciscoScanner.js.map +1 -0
- package/dist/lib/decisionsLogRefresh.d.ts +28 -0
- package/dist/lib/decisionsLogRefresh.d.ts.map +1 -0
- package/dist/lib/decisionsLogRefresh.js +54 -0
- package/dist/lib/decisionsLogRefresh.js.map +1 -0
- package/dist/lib/deviceReport.d.ts +26 -0
- package/dist/lib/deviceReport.d.ts.map +1 -0
- package/dist/lib/deviceReport.js +55 -0
- package/dist/lib/deviceReport.js.map +1 -0
- package/dist/lib/elevation.d.ts +58 -0
- package/dist/lib/elevation.d.ts.map +1 -0
- package/dist/lib/elevation.js +83 -0
- package/dist/lib/elevation.js.map +1 -0
- package/dist/lib/enforcementState.d.ts +69 -0
- package/dist/lib/enforcementState.d.ts.map +1 -0
- package/dist/lib/enforcementState.js +113 -0
- package/dist/lib/enforcementState.js.map +1 -0
- package/dist/lib/ensureValkey.d.ts.map +1 -1
- package/dist/lib/ensureValkey.js +2 -2
- package/dist/lib/ensureValkey.js.map +1 -1
- package/dist/lib/envInjector.d.ts.map +1 -1
- package/dist/lib/envInjector.js +22 -4
- package/dist/lib/envInjector.js.map +1 -1
- package/dist/lib/gitHooks.d.ts +7 -2
- package/dist/lib/gitHooks.d.ts.map +1 -1
- package/dist/lib/gitHooks.js +180 -13
- package/dist/lib/gitHooks.js.map +1 -1
- package/dist/lib/gracefulShutdown.d.ts +37 -0
- package/dist/lib/gracefulShutdown.d.ts.map +1 -0
- package/dist/lib/gracefulShutdown.js +57 -0
- package/dist/lib/gracefulShutdown.js.map +1 -0
- package/dist/lib/graphIdentity.d.ts +80 -0
- package/dist/lib/graphIdentity.d.ts.map +1 -0
- package/dist/lib/graphIdentity.js +120 -0
- package/dist/lib/graphIdentity.js.map +1 -0
- package/dist/lib/localTraces.d.ts +61 -0
- package/dist/lib/localTraces.d.ts.map +1 -0
- package/dist/lib/localTraces.js +173 -0
- package/dist/lib/localTraces.js.map +1 -0
- package/dist/lib/mdmManifest.d.ts +73 -0
- package/dist/lib/mdmManifest.d.ts.map +1 -0
- package/dist/lib/mdmManifest.js +190 -0
- package/dist/lib/mdmManifest.js.map +1 -0
- package/dist/lib/onboarding.d.ts.map +1 -1
- package/dist/lib/onboarding.js +60 -1
- package/dist/lib/onboarding.js.map +1 -1
- package/dist/lib/otelPropagation.d.ts +26 -0
- package/dist/lib/otelPropagation.d.ts.map +1 -0
- package/dist/lib/otelPropagation.js +40 -0
- package/dist/lib/otelPropagation.js.map +1 -0
- package/dist/lib/policySnapshot.d.ts +92 -0
- package/dist/lib/policySnapshot.d.ts.map +1 -0
- package/dist/lib/policySnapshot.js +173 -0
- package/dist/lib/policySnapshot.js.map +1 -0
- package/dist/lib/process.d.ts.map +1 -1
- package/dist/lib/process.js +60 -0
- package/dist/lib/process.js.map +1 -1
- package/dist/lib/providerProbe.d.ts +28 -0
- package/dist/lib/providerProbe.d.ts.map +1 -0
- package/dist/lib/providerProbe.js +57 -0
- package/dist/lib/providerProbe.js.map +1 -0
- package/dist/lib/proxyBinary.d.ts +19 -0
- package/dist/lib/proxyBinary.d.ts.map +1 -0
- package/dist/lib/proxyBinary.js +30 -0
- package/dist/lib/proxyBinary.js.map +1 -0
- package/dist/lib/sandbox/firecracker.d.ts +89 -0
- package/dist/lib/sandbox/firecracker.d.ts.map +1 -0
- package/dist/lib/sandbox/firecracker.js +135 -0
- package/dist/lib/sandbox/firecracker.js.map +1 -0
- package/dist/lib/sandbox/index.d.ts +34 -0
- package/dist/lib/sandbox/index.d.ts.map +1 -0
- package/dist/lib/sandbox/index.js +54 -0
- package/dist/lib/sandbox/index.js.map +1 -0
- package/dist/lib/sandbox/oci.d.ts +38 -0
- package/dist/lib/sandbox/oci.d.ts.map +1 -0
- package/dist/lib/sandbox/oci.js +108 -0
- package/dist/lib/sandbox/oci.js.map +1 -0
- package/dist/lib/sandbox/types.d.ts +48 -0
- package/dist/lib/sandbox/types.d.ts.map +1 -0
- package/dist/lib/sandbox/types.js +12 -0
- package/dist/lib/sandbox/types.js.map +1 -0
- package/dist/lib/sopFrontMatter.d.ts +50 -0
- package/dist/lib/sopFrontMatter.d.ts.map +1 -0
- package/dist/lib/sopFrontMatter.js +129 -0
- package/dist/lib/sopFrontMatter.js.map +1 -0
- package/package.json +11 -6
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `intutic integrity` — check that sealed trace roots still re-derive.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* - `intutic integrity roots [--loop-run <id>] [--json]`
|
|
6
|
+
* - `intutic integrity verify <root_id> [--json]`
|
|
7
|
+
* - `intutic integrity chain [--json]`
|
|
8
|
+
* - `intutic integrity config-chain [--json]`
|
|
9
|
+
*
|
|
10
|
+
* The exit status is the point. This is what a customer puts in CI, so the
|
|
11
|
+
* findings that mean "the record no longer matches what was sealed" — a
|
|
12
|
+
* re-derivation mismatch, a covered trace that is gone, a signature a published
|
|
13
|
+
* key rejects, a break in the root chain, a break or an edited body in the
|
|
14
|
+
* config snapshot chain — leave with 1. Everything else leaves with 0,
|
|
15
|
+
* including the states that look alarming and are not: a root sealed under a
|
|
16
|
+
* key that is no longer published, and a root or snapshot that names no
|
|
17
|
+
* predecessor. See `failsIntegrity`.
|
|
18
|
+
*
|
|
19
|
+
* Server side: services/control-plane/src/routes/integrity.ts.
|
|
20
|
+
*
|
|
21
|
+
* @module
|
|
22
|
+
*/
|
|
23
|
+
import { createPublicKey, verify as nodeVerify } from 'node:crypto';
|
|
24
|
+
import { log } from '../lib/logger.js';
|
|
25
|
+
import { NOT_AUTHENTICATED } from '../lib/authMessages.js';
|
|
26
|
+
import { loadCredentials } from '../config/store.js';
|
|
27
|
+
import { resolveControlPlaneUrl } from '../config/paths.js';
|
|
28
|
+
import { createApiClient } from '../lib/api.js';
|
|
29
|
+
import pc from 'picocolors';
|
|
30
|
+
/** The version to rebuild a root's preimage under. See the field's note above. */
|
|
31
|
+
function preimageVersionOf(root) {
|
|
32
|
+
return root.signing_preimage_version ?? 1;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Domain tag per preimage version, mirroring `SIGN_DOMAIN` in
|
|
36
|
+
* services/control-plane/src/lib/rootSigner.ts. This map is also the list of
|
|
37
|
+
* versions this build can rebuild — kept as one thing rather than two, because
|
|
38
|
+
* two lists of the same fact drift and the drift is silent.
|
|
39
|
+
*/
|
|
40
|
+
const SIGN_DOMAIN = {
|
|
41
|
+
1: 'intutic.merkle-root.v1',
|
|
42
|
+
2: 'intutic.merkle-root.v2',
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Whether a finding should fail the command, and therefore the customer's CI.
|
|
46
|
+
*
|
|
47
|
+
* `unverifiable` deliberately does not. A root whose `signing_key_id` is not in
|
|
48
|
+
* the published JWKS says the operator dropped a rotated-out key from
|
|
49
|
+
* `TRACE_SIGNING_RETIRED_KEYS`; a root whose `signing_preimage_version` this
|
|
50
|
+
* build does not know says the CLI is older than the control plane. Neither
|
|
51
|
+
* says anything is wrong with the root. Failing on either accuses them of
|
|
52
|
+
* rewriting history over a key-management gap or a version skew, which is the
|
|
53
|
+
* distinction rootSigner.ts exists to preserve.
|
|
54
|
+
*
|
|
55
|
+
* `keys_unavailable` does not either — a control plane we could not reach for
|
|
56
|
+
* the JWKS is a fact about the network, not about the root.
|
|
57
|
+
*
|
|
58
|
+
* A chain finding reads `breaks` and never `unchainedRootIds`: an unchained
|
|
59
|
+
* root claimed no predecessor, so it contradicts nothing. It is also what a
|
|
60
|
+
* pre-migration-108 writer produces during a rolling deploy, so failing on it
|
|
61
|
+
* would make every deploy red.
|
|
62
|
+
*
|
|
63
|
+
* `configChain` fails on either of its two findings, and they are carried as
|
|
64
|
+
* two counts rather than one total because they have different causes: a break
|
|
65
|
+
* means a snapshot beside this one went missing, a content mismatch means this
|
|
66
|
+
* snapshot's own body was rewritten under its stored hash. Both contradict a
|
|
67
|
+
* claim the writer made, so both are failures — but a caller that had only a
|
|
68
|
+
* sum could not tell an operator which happened.
|
|
69
|
+
*/
|
|
70
|
+
export function failsIntegrity(finding) {
|
|
71
|
+
switch (finding.kind) {
|
|
72
|
+
case 'recompute':
|
|
73
|
+
return finding.verdict !== 'match';
|
|
74
|
+
case 'signature':
|
|
75
|
+
return finding.state === 'invalid';
|
|
76
|
+
case 'chain':
|
|
77
|
+
return finding.breaks > 0;
|
|
78
|
+
case 'configChain':
|
|
79
|
+
return finding.breaks > 0 || finding.contentMismatches > 0;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// ─── Signature verification ─────────────────────────────────────────
|
|
83
|
+
/**
|
|
84
|
+
* The exact bytes the control plane signs, per preimage version.
|
|
85
|
+
*
|
|
86
|
+
* Must stay byte-identical to `signingPreimage` in
|
|
87
|
+
* services/control-plane/src/lib/rootSigner.ts — this is an independent
|
|
88
|
+
* verifier, so it rebuilds the preimage rather than being handed it. The scope
|
|
89
|
+
* fields are in the preimage because a signature over the bare 32-byte root
|
|
90
|
+
* would be portable to another workspace's row.
|
|
91
|
+
*
|
|
92
|
+
* v1 is the encoding of migration 107 and is retained verbatim: roots sealed
|
|
93
|
+
* under it are still in the ledger, and rebuilding them any other way reports a
|
|
94
|
+
* forgery on rows nobody touched. v2 adds `previous_root` behind a presence
|
|
95
|
+
* tag, because without it the chain link that makes root deletion detectable
|
|
96
|
+
* sat outside the signature and could be rewritten freely.
|
|
97
|
+
*
|
|
98
|
+
* The version comes off the root itself and is never a parameter. A caller that
|
|
99
|
+
* could pass one is a caller that can pass the wrong one, and the wrong one
|
|
100
|
+
* produces `invalid` — the verdict that accuses an operator of forgery.
|
|
101
|
+
*/
|
|
102
|
+
export function signingPreimage(root) {
|
|
103
|
+
const US = '\x1f';
|
|
104
|
+
const version = preimageVersionOf(root);
|
|
105
|
+
const domain = SIGN_DOMAIN[version];
|
|
106
|
+
if (domain === undefined) {
|
|
107
|
+
// Unreachable from `verifyRootSignature`, which reports an unknown version
|
|
108
|
+
// as unverifiable before it gets here. It throws rather than falling back
|
|
109
|
+
// to the newest encoding because a fallback would confidently produce bytes
|
|
110
|
+
// that were never signed, and the key would then say "forged".
|
|
111
|
+
throw new RangeError(`integrity: unknown signing preimage version ${version}`);
|
|
112
|
+
}
|
|
113
|
+
const fields = [
|
|
114
|
+
domain,
|
|
115
|
+
root.workspace_id,
|
|
116
|
+
root.loop_run_id ?? '',
|
|
117
|
+
String(root.leaf_schema_version),
|
|
118
|
+
root.merkle_root,
|
|
119
|
+
];
|
|
120
|
+
if (version >= 2) {
|
|
121
|
+
// Presence tag then value, matching rootSigner.ts. "No predecessor" is a
|
|
122
|
+
// claim about the chain, not a missing field, so it must not encode the
|
|
123
|
+
// same as some value could.
|
|
124
|
+
//
|
|
125
|
+
// Normalised through `?? null` rather than compared against `null` directly:
|
|
126
|
+
// this row is parsed from JSON, and a server that omits the key rather than
|
|
127
|
+
// serialising a null would otherwise be tagged present-with-empty-value here
|
|
128
|
+
// while the control plane and the dashboard both tag it absent. Two of our
|
|
129
|
+
// own verifiers disagreeing on one root is how an auditor gets handed a
|
|
130
|
+
// forgery verdict we manufactured.
|
|
131
|
+
const previous = root.previous_root ?? null;
|
|
132
|
+
fields.push(previous === null ? '0' : '1', previous ?? '');
|
|
133
|
+
}
|
|
134
|
+
return fields.join(US);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check a root's signature against the key the root itself names.
|
|
138
|
+
*
|
|
139
|
+
* Selection is by `signing_key_id`, never "any key that works": a root sealed
|
|
140
|
+
* under a rotated-out key must verify against that key years later, and a root
|
|
141
|
+
* that verifies under some *other* published key is not the same claim.
|
|
142
|
+
*/
|
|
143
|
+
export function verifyRootSignature(root, jwks) {
|
|
144
|
+
if (!root.signature || !root.signing_key_id)
|
|
145
|
+
return 'unsigned';
|
|
146
|
+
if (!jwks)
|
|
147
|
+
return 'keys_unavailable';
|
|
148
|
+
const jwk = jwks.keys.find((k) => k['kid'] === root.signing_key_id);
|
|
149
|
+
if (!jwk)
|
|
150
|
+
return 'unverifiable';
|
|
151
|
+
// An algorithm this build cannot compute is another "no verdict", not a
|
|
152
|
+
// rejection. Only EdDSA is ever written today (rootSigner.ts signs nothing
|
|
153
|
+
// else), so this is the forward-compatible branch.
|
|
154
|
+
if (root.signature_alg !== 'EdDSA')
|
|
155
|
+
return 'unverifiable';
|
|
156
|
+
// And exactly the same for a preimage this build cannot rebuild. A newer
|
|
157
|
+
// control plane sealing under v3 while a customer's CI still runs last
|
|
158
|
+
// quarter's CLI is the ordinary case. Whatever bytes we produced for it would
|
|
159
|
+
// not be the bytes that were signed, so we would either print INVALID and
|
|
160
|
+
// exit 1 over a version skew, or — worse — reconstruct something that happens
|
|
161
|
+
// to match and report `valid` for a check we did not actually perform.
|
|
162
|
+
// Nothing here settles it either way, which is what `unverifiable` means.
|
|
163
|
+
if (SIGN_DOMAIN[preimageVersionOf(root)] === undefined)
|
|
164
|
+
return 'unverifiable';
|
|
165
|
+
try {
|
|
166
|
+
const key = createPublicKey({ key: jwk, format: 'jwk' });
|
|
167
|
+
const ok = nodeVerify(null, Buffer.from(signingPreimage(root), 'utf8'), key, Buffer.from(root.signature, 'base64'));
|
|
168
|
+
return ok ? 'valid' : 'invalid';
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// A published key we cannot load is a key we do not effectively hold. That
|
|
172
|
+
// is the unverifiable case, not a rejection by a key we do hold.
|
|
173
|
+
return 'unverifiable';
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/** Where the verification keys are published. Unauthenticated by design. */
|
|
177
|
+
const JWKS_PATH = '/.well-known/intutic-trace-signing.json';
|
|
178
|
+
/**
|
|
179
|
+
* Fetch the published verification keys, or null when they cannot be had.
|
|
180
|
+
*
|
|
181
|
+
* No credentials: an auditor who must hold your API key to obtain the verifying
|
|
182
|
+
* key is not an external auditor, and this command must exercise the same path
|
|
183
|
+
* one of them would.
|
|
184
|
+
*/
|
|
185
|
+
async function fetchSigningKeys(controlPlaneUrl) {
|
|
186
|
+
try {
|
|
187
|
+
const res = await fetch(`${controlPlaneUrl}${JWKS_PATH}`);
|
|
188
|
+
if (!res.ok)
|
|
189
|
+
return null;
|
|
190
|
+
const body = (await res.json());
|
|
191
|
+
return Array.isArray(body?.keys) ? body : null;
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// ─── Formatting helpers ─────────────────────────────────────────────
|
|
198
|
+
/** Truncate an id for table display. */
|
|
199
|
+
function truncateId(id) {
|
|
200
|
+
if (id.length <= 20)
|
|
201
|
+
return id;
|
|
202
|
+
return id.slice(0, 17) + '...';
|
|
203
|
+
}
|
|
204
|
+
/** Format ISO timestamp for compact table display. */
|
|
205
|
+
function formatTimestamp(iso) {
|
|
206
|
+
if (!iso)
|
|
207
|
+
return '—';
|
|
208
|
+
const d = new Date(iso);
|
|
209
|
+
const pad2 = (n) => String(n).padStart(2, '0');
|
|
210
|
+
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())} ${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
|
|
211
|
+
}
|
|
212
|
+
/** Pad a string to a fixed width (right-pad with spaces). */
|
|
213
|
+
/**
|
|
214
|
+
* ANSI escapes are zero-width. Measuring and slicing raw string length counts
|
|
215
|
+
* them, so a coloured cell is both mis-padded and cut mid-escape.
|
|
216
|
+
*
|
|
217
|
+
* `pc.yellow('unverifiable')` is 22 characters of which 12 are visible. Against
|
|
218
|
+
* a 13-wide column the old `slice(0, width)` cut after `ESC[33munver`, leaving a
|
|
219
|
+
* truncated word and an unterminated escape sequence that bleeds colour into
|
|
220
|
+
* everything after it. It looked fine locally only because picocolors disables
|
|
221
|
+
* colour when stdout is not a TTY — so the bug was invisible in a pipe and
|
|
222
|
+
* present in every real terminal.
|
|
223
|
+
*/
|
|
224
|
+
// eslint-disable-next-line no-control-regex -- ESC (\u001b) opens every SGR colour sequence; matching it is this pattern's whole purpose.
|
|
225
|
+
const ANSI = /\u001b\[[0-9;]*m/g;
|
|
226
|
+
function visibleLength(str) {
|
|
227
|
+
return str.replace(ANSI, '').length;
|
|
228
|
+
}
|
|
229
|
+
/** Cut to `width` VISIBLE characters, keeping escapes and closing any left open. */
|
|
230
|
+
function truncateVisible(str, width) {
|
|
231
|
+
let out = '';
|
|
232
|
+
let seen = 0;
|
|
233
|
+
let i = 0;
|
|
234
|
+
let coloured = false;
|
|
235
|
+
while (i < str.length && seen < width) {
|
|
236
|
+
ANSI.lastIndex = i;
|
|
237
|
+
const m = ANSI.exec(str);
|
|
238
|
+
if (m && m.index === i) {
|
|
239
|
+
out += m[0];
|
|
240
|
+
coloured = m[0] !== '\u001b[39m' && m[0] !== '\u001b[0m';
|
|
241
|
+
i += m[0].length;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
out += str[i];
|
|
245
|
+
seen += 1;
|
|
246
|
+
i += 1;
|
|
247
|
+
}
|
|
248
|
+
// Never leave a colour open — it would tint the border and every later row.
|
|
249
|
+
return coloured ? out + '\u001b[0m' : out;
|
|
250
|
+
}
|
|
251
|
+
export function padCell(str, width) {
|
|
252
|
+
const visible = visibleLength(str);
|
|
253
|
+
if (visible >= width)
|
|
254
|
+
return truncateVisible(str, width);
|
|
255
|
+
return str + ' '.repeat(width - visible);
|
|
256
|
+
}
|
|
257
|
+
/** Render a simple table with borders. */
|
|
258
|
+
function renderTable(headers, widths, rows) {
|
|
259
|
+
const top = '┌' + widths.map((w) => '─'.repeat(w + 2)).join('┬') + '┐';
|
|
260
|
+
const mid = '├' + widths.map((w) => '─'.repeat(w + 2)).join('┼') + '┤';
|
|
261
|
+
const bot = '└' + widths.map((w) => '─'.repeat(w + 2)).join('┴') + '┘';
|
|
262
|
+
const fmtRow = (cells) => '│ ' + cells.map((c, i) => padCell(c, widths[i])).join(' │ ') + ' │';
|
|
263
|
+
console.log(top);
|
|
264
|
+
console.log(fmtRow(headers));
|
|
265
|
+
console.log(mid);
|
|
266
|
+
for (const row of rows) {
|
|
267
|
+
console.log(fmtRow(row));
|
|
268
|
+
}
|
|
269
|
+
console.log(bot);
|
|
270
|
+
}
|
|
271
|
+
export function keyPublication(row, jwks) {
|
|
272
|
+
if (!row.signing_key_id)
|
|
273
|
+
return 'unsigned';
|
|
274
|
+
if (!jwks)
|
|
275
|
+
return 'keys_unavailable';
|
|
276
|
+
return jwks.keys.some((k) => k['kid'] === row.signing_key_id) ? 'published' : 'not_published';
|
|
277
|
+
}
|
|
278
|
+
/** Colour a key-publication state for the listing. */
|
|
279
|
+
function colorPublication(state) {
|
|
280
|
+
switch (state) {
|
|
281
|
+
case 'published':
|
|
282
|
+
return pc.cyan('key published');
|
|
283
|
+
case 'not_published':
|
|
284
|
+
return pc.yellow('unverifiable');
|
|
285
|
+
case 'keys_unavailable':
|
|
286
|
+
return pc.yellow('keys unread');
|
|
287
|
+
case 'unsigned':
|
|
288
|
+
return pc.dim('unsigned');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/** Colour a signature state. Amber for "no verdict", red only for a rejection. */
|
|
292
|
+
function colorSignature(state) {
|
|
293
|
+
switch (state) {
|
|
294
|
+
case 'valid':
|
|
295
|
+
return pc.green('valid');
|
|
296
|
+
case 'invalid':
|
|
297
|
+
return pc.red('INVALID');
|
|
298
|
+
case 'unverifiable':
|
|
299
|
+
return pc.yellow('unverifiable');
|
|
300
|
+
case 'keys_unavailable':
|
|
301
|
+
return pc.yellow('not checked');
|
|
302
|
+
case 'unsigned':
|
|
303
|
+
return pc.dim('unsigned');
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/** What each signature state means, and what the operator does about it. */
|
|
307
|
+
function signatureNote(state, controlPlaneUrl) {
|
|
308
|
+
switch (state) {
|
|
309
|
+
case 'valid':
|
|
310
|
+
return 'Signed by a key this deployment publishes. That proves the root came from this deployment — not that its history is true, since the same party holds the key.';
|
|
311
|
+
case 'invalid':
|
|
312
|
+
return 'The key this root names REJECTED its signature. The root does not say what it was sealed saying.';
|
|
313
|
+
case 'unverifiable':
|
|
314
|
+
return `Nothing here settles this either way: either the key id it was sealed under is not published at ${controlPlaneUrl}${JWKS_PATH} — put the rotated-out PEM back into TRACE_SIGNING_RETIRED_KEYS — or the root records a signing preimage version this CLI cannot rebuild, in which case upgrade the CLI.`;
|
|
315
|
+
case 'keys_unavailable':
|
|
316
|
+
return `Could not read ${controlPlaneUrl}${JWKS_PATH}, so the signature was not checked.`;
|
|
317
|
+
case 'unsigned':
|
|
318
|
+
return 'Sealed with no signing key configured. Supported — the root still re-derives; it just cannot be attributed to this deployment by a third party.';
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
/** Cap a long id list so a mismatch over 4,000 traces stays readable. */
|
|
322
|
+
function sampleIds(ids, limit = 10) {
|
|
323
|
+
if (ids.length <= limit)
|
|
324
|
+
return ids.join(', ');
|
|
325
|
+
return `${ids.slice(0, limit).join(', ')} … and ${ids.length - limit} more`;
|
|
326
|
+
}
|
|
327
|
+
// ─── Commands ───────────────────────────────────────────────────────
|
|
328
|
+
/**
|
|
329
|
+
* `intutic integrity roots` — the sealed roots for the workspace, newest first.
|
|
330
|
+
*/
|
|
331
|
+
export async function runIntegrityRoots(opts) {
|
|
332
|
+
const creds = await loadCredentials();
|
|
333
|
+
if (!creds) {
|
|
334
|
+
log.error(NOT_AUTHENTICATED);
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
const controlPlaneUrl = resolveControlPlaneUrl(opts.dev);
|
|
338
|
+
const client = createApiClient(controlPlaneUrl, creds.apiKey);
|
|
339
|
+
try {
|
|
340
|
+
const query = opts.loopRun ? `?loopRunId=${encodeURIComponent(opts.loopRun)}` : '';
|
|
341
|
+
const data = await client.get(`/api/v1/integrity/roots${query}`);
|
|
342
|
+
const roots = data.data ?? [];
|
|
343
|
+
if (opts.json) {
|
|
344
|
+
console.log(JSON.stringify(data, null, 2));
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
log.header('Intutic — Sealed Trace Roots');
|
|
348
|
+
if (roots.length === 0) {
|
|
349
|
+
log.dim(' No roots sealed yet.');
|
|
350
|
+
log.dim(' An hourly sweep seals a loop run once it is terminal and has been quiet for');
|
|
351
|
+
log.dim(' fifteen minutes. Until then its traces are recorded but under no root.');
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
// Fetched once for the whole listing. Without it the signature column could
|
|
355
|
+
// only report presence, and "signed" would be indistinguishable from
|
|
356
|
+
// "signed by a key nobody can obtain".
|
|
357
|
+
const jwks = await fetchSigningKeys(controlPlaneUrl);
|
|
358
|
+
const headers = ['Root ID', 'Sealed', 'Loop Run', 'Traces', 'Leaf v', 'Signature'];
|
|
359
|
+
const widths = [20, 16, 20, 6, 6, 13];
|
|
360
|
+
const rows = roots.map((r) => [
|
|
361
|
+
truncateId(r.root_id),
|
|
362
|
+
formatTimestamp(r.sealed_at),
|
|
363
|
+
r.loop_run_id ? truncateId(r.loop_run_id) : '—',
|
|
364
|
+
String(r.leaf_count),
|
|
365
|
+
`v${r.leaf_schema_version}`,
|
|
366
|
+
// The list endpoint does not carry the signature itself, so this column
|
|
367
|
+
// reports key publication and nothing more. `verify` checks the bytes.
|
|
368
|
+
colorPublication(keyPublication(r, jwks)),
|
|
369
|
+
]);
|
|
370
|
+
renderTable(headers, widths, rows);
|
|
371
|
+
console.log(pc.dim(`Showing ${roots.length} root${roots.length === 1 ? '' : 's'}. The Signature column reports whether the sealing key is published,\n` +
|
|
372
|
+
'not whether the signature verifies — `intutic integrity verify <root_id>` checks the bytes.'));
|
|
373
|
+
}
|
|
374
|
+
catch (err) {
|
|
375
|
+
log.error(`Failed to list roots: ${err instanceof Error ? err.message : String(err)}`);
|
|
376
|
+
process.exit(1);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* `intutic integrity verify <root_id>` — re-derive one root from the live rows
|
|
381
|
+
* and check its signature.
|
|
382
|
+
*
|
|
383
|
+
* Exits 1 on a mismatch, on missing traces, or on a signature a published key
|
|
384
|
+
* rejects.
|
|
385
|
+
*/
|
|
386
|
+
export async function runIntegrityVerify(rootId, opts) {
|
|
387
|
+
const creds = await loadCredentials();
|
|
388
|
+
if (!creds) {
|
|
389
|
+
log.error(NOT_AUTHENTICATED);
|
|
390
|
+
process.exit(1);
|
|
391
|
+
}
|
|
392
|
+
const controlPlaneUrl = resolveControlPlaneUrl(opts.dev);
|
|
393
|
+
const client = createApiClient(controlPlaneUrl, creds.apiKey);
|
|
394
|
+
const encoded = encodeURIComponent(rootId);
|
|
395
|
+
let detail;
|
|
396
|
+
let recompute;
|
|
397
|
+
try {
|
|
398
|
+
detail = await client.get(`/api/v1/integrity/roots/${encoded}`);
|
|
399
|
+
// Always 200, whatever the verdict: a mismatch is a successful check that
|
|
400
|
+
// found something, and an HTTP error here would be retried and then ignored.
|
|
401
|
+
recompute = await client.post(`/api/v1/integrity/roots/${encoded}/recompute`, {});
|
|
402
|
+
}
|
|
403
|
+
catch (err) {
|
|
404
|
+
log.error(`Failed to verify root: ${err instanceof Error ? err.message : String(err)}`);
|
|
405
|
+
process.exit(1);
|
|
406
|
+
}
|
|
407
|
+
const signature = verifyRootSignature(detail.root, await fetchSigningKeys(controlPlaneUrl));
|
|
408
|
+
const findings = [
|
|
409
|
+
{ kind: 'recompute', verdict: recompute.verdict },
|
|
410
|
+
{ kind: 'signature', state: signature },
|
|
411
|
+
];
|
|
412
|
+
const failed = findings.some(failsIntegrity);
|
|
413
|
+
if (opts.json) {
|
|
414
|
+
console.log(JSON.stringify({
|
|
415
|
+
rootId,
|
|
416
|
+
verdict: recompute.verdict,
|
|
417
|
+
storedRoot: recompute.storedRoot,
|
|
418
|
+
recomputedRoot: recompute.recomputedRoot,
|
|
419
|
+
changedTraceIds: recompute.changedTraceIds,
|
|
420
|
+
missingTraceIds: recompute.missingTraceIds,
|
|
421
|
+
signature,
|
|
422
|
+
leafSchemaVersion: detail.root.leaf_schema_version,
|
|
423
|
+
leafCount: detail.root.leaf_count,
|
|
424
|
+
failed,
|
|
425
|
+
}, null, 2));
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
log.header('Intutic — Root Verification');
|
|
429
|
+
log.field('Root ID', detail.root.root_id);
|
|
430
|
+
log.field('Loop run', detail.root.loop_run_id ?? '— (not scoped to a run)');
|
|
431
|
+
log.field('Sealed', formatTimestamp(detail.root.sealed_at));
|
|
432
|
+
log.field('Traces covered', `${detail.leaves.length} of ${detail.root.leaf_count} enumerated`);
|
|
433
|
+
log.field('Leaf schema', `v${detail.root.leaf_schema_version}`);
|
|
434
|
+
console.log('');
|
|
435
|
+
switch (recompute.verdict) {
|
|
436
|
+
case 'match':
|
|
437
|
+
log.success('Re-derivation: match — every covered trace still hashes to what was sealed.');
|
|
438
|
+
break;
|
|
439
|
+
case 'mismatch':
|
|
440
|
+
log.error(`Re-derivation: MISMATCH — ${recompute.changedTraceIds.length} trace(s) changed after sealing.`);
|
|
441
|
+
log.field('Changed', sampleIds(recompute.changedTraceIds));
|
|
442
|
+
log.field('Sealed root', recompute.storedRoot);
|
|
443
|
+
log.field('Re-derived', recompute.recomputedRoot ?? '—');
|
|
444
|
+
break;
|
|
445
|
+
case 'missing_traces':
|
|
446
|
+
log.error(`Re-derivation: MISSING TRACES — ${recompute.missingTraceIds.length} covered trace(s) are gone.`);
|
|
447
|
+
log.field('Missing', sampleIds(recompute.missingTraceIds));
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
console.log('');
|
|
451
|
+
console.log(` ${pc.dim('Signature:')} ${colorSignature(signature)}`);
|
|
452
|
+
log.dim(` ${signatureNote(signature, controlPlaneUrl)}`);
|
|
453
|
+
}
|
|
454
|
+
if (failed)
|
|
455
|
+
process.exit(1);
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* `intutic integrity chain` — walk the `previous_root` chain.
|
|
459
|
+
*
|
|
460
|
+
* Exits 1 on a break. Re-derivation cannot see a root that was deleted outright
|
|
461
|
+
* — the survivors all verify perfectly — so this walk is the only check that
|
|
462
|
+
* notices one is missing.
|
|
463
|
+
*/
|
|
464
|
+
export async function runIntegrityChain(opts) {
|
|
465
|
+
const creds = await loadCredentials();
|
|
466
|
+
if (!creds) {
|
|
467
|
+
log.error(NOT_AUTHENTICATED);
|
|
468
|
+
process.exit(1);
|
|
469
|
+
}
|
|
470
|
+
const controlPlaneUrl = resolveControlPlaneUrl(opts.dev);
|
|
471
|
+
const client = createApiClient(controlPlaneUrl, creds.apiKey);
|
|
472
|
+
let status;
|
|
473
|
+
let body;
|
|
474
|
+
try {
|
|
475
|
+
// The break case answers 409 with the walk in the body, so the status
|
|
476
|
+
// cannot be allowed to throw past the reporting.
|
|
477
|
+
const res = await client.getWithStatus('/api/v1/integrity/chain');
|
|
478
|
+
status = res.status;
|
|
479
|
+
body = res.body;
|
|
480
|
+
}
|
|
481
|
+
catch (err) {
|
|
482
|
+
log.error(`Failed to walk the chain: ${err instanceof Error ? err.message : String(err)}`);
|
|
483
|
+
process.exit(1);
|
|
484
|
+
}
|
|
485
|
+
if (status !== 200 && status !== 409) {
|
|
486
|
+
log.error(`Chain walk failed (${status}): ${JSON.stringify(body)}`);
|
|
487
|
+
process.exit(1);
|
|
488
|
+
}
|
|
489
|
+
const breaks = body.breaks ?? [];
|
|
490
|
+
const unchained = body.unchainedRootIds ?? [];
|
|
491
|
+
if (opts.json) {
|
|
492
|
+
console.log(JSON.stringify({ ...body, failed: failsIntegrity({ kind: 'chain', breaks: breaks.length }) }, null, 2));
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
log.header('Intutic — Root Chain Walk');
|
|
496
|
+
log.field('Roots walked', String(body.rootsWalked));
|
|
497
|
+
if (body.rootsNotWalked > 0) {
|
|
498
|
+
// An unwalked tail is not an intact one, and the endpoint says so rather
|
|
499
|
+
// than letting the caller read "no breaks" as "no breaks anywhere".
|
|
500
|
+
log.field('Older, not walked', `${body.rootsNotWalked} (outside the 500-root window)`);
|
|
501
|
+
}
|
|
502
|
+
if (breaks.length === 0) {
|
|
503
|
+
log.success('No breaks: every walked root names the root that actually precedes it.');
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
log.error(`${breaks.length} break(s) — a root names a predecessor that is not the root before it.`);
|
|
507
|
+
for (const b of breaks) {
|
|
508
|
+
log.field(b.rootId, `names ${b.namedPrevious}, but ${b.precedingRootId} (${b.precedingMerkleRoot}) precedes it`);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (unchained.length > 0) {
|
|
512
|
+
log.warn(`${unchained.length} root(s) name no predecessor. Not a break — nothing was claimed, so ` +
|
|
513
|
+
'nothing contradicts. It means a deletion at that point would go unseen.');
|
|
514
|
+
log.field('Unchained', sampleIds(unchained));
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (failsIntegrity({ kind: 'chain', breaks: breaks.length }))
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* `intutic integrity config-chain` — walk the harness config snapshot chain.
|
|
522
|
+
*
|
|
523
|
+
* The TD-232 verifier, reached from the product rather than from a hand-written
|
|
524
|
+
* curl. `content_hash` and `previous_hash` are written on every config snapshot
|
|
525
|
+
* and were read only to find a diff predecessor, so for months a snapshot could
|
|
526
|
+
* be deleted, or its body rewritten under its stored hash, and every reader
|
|
527
|
+
* returned exactly what it returned before.
|
|
528
|
+
*
|
|
529
|
+
* Exits 1 on either finding. They are reported apart because they have
|
|
530
|
+
* different causes and different remedies: a break says a snapshot next to this
|
|
531
|
+
* one is gone, a content mismatch says this snapshot's own stored body no
|
|
532
|
+
* longer hashes to the hash recorded with it. Collapsing them into one count is
|
|
533
|
+
* the mistake the `audit_log_integrity` probe made by averaging independent
|
|
534
|
+
* controls into a single score.
|
|
535
|
+
*/
|
|
536
|
+
export async function runIntegrityConfigChain(opts) {
|
|
537
|
+
const creds = await loadCredentials();
|
|
538
|
+
if (!creds) {
|
|
539
|
+
log.error(NOT_AUTHENTICATED);
|
|
540
|
+
process.exit(1);
|
|
541
|
+
}
|
|
542
|
+
const controlPlaneUrl = resolveControlPlaneUrl(opts.dev);
|
|
543
|
+
const client = createApiClient(controlPlaneUrl, creds.apiKey);
|
|
544
|
+
let status;
|
|
545
|
+
let body;
|
|
546
|
+
try {
|
|
547
|
+
// Same reason as `chain` above: the contradicted case answers 409 with the
|
|
548
|
+
// walk in the body, so the status must not throw past the reporting.
|
|
549
|
+
const res = await client.getWithStatus('/api/v1/integrity/config-chain');
|
|
550
|
+
status = res.status;
|
|
551
|
+
body = res.body;
|
|
552
|
+
}
|
|
553
|
+
catch (err) {
|
|
554
|
+
log.error(`Failed to walk the config chain: ${err instanceof Error ? err.message : String(err)}`);
|
|
555
|
+
process.exit(1);
|
|
556
|
+
}
|
|
557
|
+
if (status !== 200 && status !== 409) {
|
|
558
|
+
log.error(`Config chain walk failed (${status}): ${JSON.stringify(body)}`);
|
|
559
|
+
process.exit(1);
|
|
560
|
+
}
|
|
561
|
+
const breaks = body.breaks ?? [];
|
|
562
|
+
const mismatches = body.contentMismatches ?? [];
|
|
563
|
+
const unchained = body.unchainedSnapshotIds ?? [];
|
|
564
|
+
const walked = body.snapshotsWalked ?? 0;
|
|
565
|
+
const failed = failsIntegrity({
|
|
566
|
+
kind: 'configChain',
|
|
567
|
+
breaks: breaks.length,
|
|
568
|
+
contentMismatches: mismatches.length,
|
|
569
|
+
});
|
|
570
|
+
if (opts.json) {
|
|
571
|
+
console.log(JSON.stringify({ ...body, failed }, null, 2));
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
log.header('Intutic — Config Snapshot Chain Walk');
|
|
575
|
+
log.field('Snapshots walked', String(walked));
|
|
576
|
+
if (body.snapshotsNotWalked > 0) {
|
|
577
|
+
// Never printed as a count: the server stops counting at one. An
|
|
578
|
+
// unwalked tail is still not an intact one, so it is stated.
|
|
579
|
+
log.field('Older, not walked', 'yes — snapshots past the 500-snapshot window were not examined');
|
|
580
|
+
}
|
|
581
|
+
if (walked === 0) {
|
|
582
|
+
// Not a pass, and it must not read as one. Nothing was checked, so
|
|
583
|
+
// "no breaks" here would be the same sentence an intact chain prints
|
|
584
|
+
// while standing for nothing at all.
|
|
585
|
+
log.warn('No config snapshots for this workspace, so nothing was verified. This is not a clean ' +
|
|
586
|
+
'chain — it is an absent one. A workspace whose harness configs are being captured ' +
|
|
587
|
+
'has snapshots; if this one should, the sync daemon is not reaching the control plane.');
|
|
588
|
+
}
|
|
589
|
+
else if (breaks.length === 0 && mismatches.length === 0) {
|
|
590
|
+
log.success(`No breaks and no content mismatches across ${walked} snapshot(s): every walked snapshot ` +
|
|
591
|
+
'names the snapshot that actually precedes it, and every stored body still hashes to its ' +
|
|
592
|
+
'recorded content_hash.');
|
|
593
|
+
}
|
|
594
|
+
if (breaks.length > 0) {
|
|
595
|
+
log.error(`${breaks.length} break(s) — a snapshot names a predecessor that is not the snapshot ` +
|
|
596
|
+
'before it. That is what deleting a snapshot leaves behind.');
|
|
597
|
+
for (const b of breaks) {
|
|
598
|
+
log.field(`${b.snapshotId} (${b.harnessType} ${b.filePath})`, `names ${b.namedPrevious}, but ${b.precedingSnapshotId} (${b.precedingContentHash}) precedes it`);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (mismatches.length > 0) {
|
|
602
|
+
// Deliberately not called a break, and deliberately printed as its own
|
|
603
|
+
// finding: the links here are all intact. The body under one of them was
|
|
604
|
+
// edited, which link-checking alone cannot see.
|
|
605
|
+
log.error(`${mismatches.length} content mismatch(es) — a stored snapshot body no longer hashes to ` +
|
|
606
|
+
'the content_hash recorded with it. The body was rewritten in place.');
|
|
607
|
+
for (const m of mismatches) {
|
|
608
|
+
log.field(`${m.snapshotId} (${m.harnessType} ${m.filePath})`, `recorded ${m.storedHash}, body now hashes to ${m.recomputedHash}`);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (unchained.length > 0) {
|
|
612
|
+
log.warn(`${unchained.length} snapshot(s) name no predecessor mid-chain. Nothing was claimed, so ` +
|
|
613
|
+
'nothing contradicts — but a deletion at that point would go unseen.');
|
|
614
|
+
log.field('Unchained', sampleIds(unchained));
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if (failed)
|
|
618
|
+
process.exit(1);
|
|
619
|
+
}
|
|
620
|
+
//# sourceMappingURL=integrity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrity.js","sourceRoot":"","sources":["../../src/commands/integrity.ts"],"names":[],"mappings":"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"}
|