@intutic/cli 1.9.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 @@
|
|
|
1
|
+
{"version":3,"file":"proxyBinary.js","sourceRoot":"","sources":["../../src/lib/proxyBinary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,SAAS,MAAM,WAAW,CAAA;AACtC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,MAAM,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAwB,CAAA;AAE/F;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;IACtD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,iBAAiB,OAAO,GAAG,GAAG,EAAE,CAAC,CAAA;IAC1F,OAAO,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA;AACzD,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,kBAAkB;IAChC,OAAO,gBAAgB,EAAE,IAAI,eAAe,CAAA;AAC9C,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FirecrackerBackend — VM-grade isolation via a Firecracker microVM (LLD #63 §6,
|
|
3
|
+
* Increment 4). Same `SandboxBackend` interface as the container backend; the
|
|
4
|
+
* difference is the boundary: a separate guest kernel over KVM rather than
|
|
5
|
+
* shared-kernel namespaces.
|
|
6
|
+
*
|
|
7
|
+
* The egress model is identical in spirit — the microVM's only route out is the
|
|
8
|
+
* governing proxy — but enforced on the *host* side, by a default-deny firewall
|
|
9
|
+
* on the guest's tap interface (the L2 rule shape, scoped to the guest's
|
|
10
|
+
* source address). That keeps the enforcement outside the guest, where the
|
|
11
|
+
* agent cannot touch it, which is stronger than the in-container firewall.
|
|
12
|
+
*
|
|
13
|
+
* Honesty status (see LLD #63 §7 + TECH_DEBT): the microVM *boots on real KVM*
|
|
14
|
+
* — validated on a GCE nested-virt host, where Firecracker loaded and ran the
|
|
15
|
+
* guest kernel through this exact config + API sequence (the launch script this
|
|
16
|
+
* backend invokes). What is NOT yet validated end-to-end is an agent running to
|
|
17
|
+
* completion *inside* a fully-booted guest: that needs a matched
|
|
18
|
+
* kernel+rootfs pair the operator supplies (as an OCI sandbox needs an image
|
|
19
|
+
* containing the agent). `health()` therefore gates on KVM + the firecracker
|
|
20
|
+
* binary + the operator-supplied kernel/rootfs, and refuses rather than
|
|
21
|
+
* pretend — it never falls back to a weaker backend.
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
*/
|
|
25
|
+
import type { SandboxBackend, SandboxHealth, SandboxSpec } from './types.js';
|
|
26
|
+
/** Firecracker-specific inputs, beyond the generic SandboxSpec. */
|
|
27
|
+
export interface FirecrackerOptions {
|
|
28
|
+
/** Guest kernel image (vmlinux). Operator-supplied. */
|
|
29
|
+
kernelPath: string;
|
|
30
|
+
/** Root filesystem image (ext4). Operator-supplied, must contain the agent. */
|
|
31
|
+
rootfsPath: string;
|
|
32
|
+
/** Host tap device name. */
|
|
33
|
+
tapDevice: string;
|
|
34
|
+
/** Guest IP on the point-to-point tap link. */
|
|
35
|
+
guestIp: string;
|
|
36
|
+
/** Host IP on the tap link — the address the guest reaches the proxy at. */
|
|
37
|
+
hostIp: string;
|
|
38
|
+
/** Netmask (prefix length) for the tap link. */
|
|
39
|
+
prefixLen: number;
|
|
40
|
+
vcpus: number;
|
|
41
|
+
memMib: number;
|
|
42
|
+
}
|
|
43
|
+
/** The Firecracker VM configuration, as `firecracker --config-file` consumes. */
|
|
44
|
+
export interface FirecrackerConfig {
|
|
45
|
+
'boot-source': {
|
|
46
|
+
kernel_image_path: string;
|
|
47
|
+
boot_args: string;
|
|
48
|
+
};
|
|
49
|
+
drives: Array<{
|
|
50
|
+
drive_id: string;
|
|
51
|
+
path_on_host: string;
|
|
52
|
+
is_root_device: boolean;
|
|
53
|
+
is_read_only: boolean;
|
|
54
|
+
}>;
|
|
55
|
+
'network-interfaces': Array<{
|
|
56
|
+
iface_id: string;
|
|
57
|
+
host_dev_name: string;
|
|
58
|
+
}>;
|
|
59
|
+
'machine-config': {
|
|
60
|
+
vcpu_count: number;
|
|
61
|
+
mem_size_mib: number;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Build the Firecracker VM config. Pure and exported so the exact boot config
|
|
66
|
+
* — the one proven to boot a guest kernel on KVM — is asserted without a VM.
|
|
67
|
+
*
|
|
68
|
+
* The boot args are load-bearing: `root=/dev/vda rw` (the rootfs is the first
|
|
69
|
+
* virtio-blk device) and the kernel `ip=` directive that configures the guest's
|
|
70
|
+
* eth0 on the point-to-point tap link so its only reachable peer is the host.
|
|
71
|
+
*/
|
|
72
|
+
export declare function buildFirecrackerConfig(opts: FirecrackerOptions): FirecrackerConfig;
|
|
73
|
+
/** Dotted-quad netmask for a prefix length (IPv4). */
|
|
74
|
+
export declare function prefixToNetmask(prefix: number): string;
|
|
75
|
+
export declare class FirecrackerBackend implements SandboxBackend {
|
|
76
|
+
readonly name = "firecracker";
|
|
77
|
+
private readonly opts;
|
|
78
|
+
private readonly env;
|
|
79
|
+
constructor(opts: FirecrackerOptions, env: Record<string, string>);
|
|
80
|
+
/**
|
|
81
|
+
* Available only where a microVM can actually run: KVM present, the
|
|
82
|
+
* firecracker binary on PATH, and the operator's kernel + rootfs readable.
|
|
83
|
+
* Any of these missing → unavailable, and the caller refuses rather than
|
|
84
|
+
* downgrade (the honesty rule).
|
|
85
|
+
*/
|
|
86
|
+
health(): Promise<SandboxHealth>;
|
|
87
|
+
run(spec: SandboxSpec): Promise<number>;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=firecracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firecracker.d.ts","sourceRoot":"","sources":["../../../src/lib/sandbox/firecracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE5E,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAA;IAClB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAA;IAClB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAA;IACf,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAA;IACd,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/D,MAAM,EAAE,KAAK,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAA;QAChB,YAAY,EAAE,MAAM,CAAA;QACpB,cAAc,EAAE,OAAO,CAAA;QACvB,YAAY,EAAE,OAAO,CAAA;KACtB,CAAC,CAAA;IACF,oBAAoB,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxE,gBAAgB,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;CAC/D;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,kBAAkB,GAAG,iBAAiB,CAkBlF;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtD;AASD,qBAAa,kBAAmB,YAAW,cAAc;IACvD,QAAQ,CAAC,IAAI,iBAAgB;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAwB;gBAEhC,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAKjE;;;;;OAKG;IACG,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;IAiBhC,GAAG,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;CAoC9C"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FirecrackerBackend — VM-grade isolation via a Firecracker microVM (LLD #63 §6,
|
|
3
|
+
* Increment 4). Same `SandboxBackend` interface as the container backend; the
|
|
4
|
+
* difference is the boundary: a separate guest kernel over KVM rather than
|
|
5
|
+
* shared-kernel namespaces.
|
|
6
|
+
*
|
|
7
|
+
* The egress model is identical in spirit — the microVM's only route out is the
|
|
8
|
+
* governing proxy — but enforced on the *host* side, by a default-deny firewall
|
|
9
|
+
* on the guest's tap interface (the L2 rule shape, scoped to the guest's
|
|
10
|
+
* source address). That keeps the enforcement outside the guest, where the
|
|
11
|
+
* agent cannot touch it, which is stronger than the in-container firewall.
|
|
12
|
+
*
|
|
13
|
+
* Honesty status (see LLD #63 §7 + TECH_DEBT): the microVM *boots on real KVM*
|
|
14
|
+
* — validated on a GCE nested-virt host, where Firecracker loaded and ran the
|
|
15
|
+
* guest kernel through this exact config + API sequence (the launch script this
|
|
16
|
+
* backend invokes). What is NOT yet validated end-to-end is an agent running to
|
|
17
|
+
* completion *inside* a fully-booted guest: that needs a matched
|
|
18
|
+
* kernel+rootfs pair the operator supplies (as an OCI sandbox needs an image
|
|
19
|
+
* containing the agent). `health()` therefore gates on KVM + the firecracker
|
|
20
|
+
* binary + the operator-supplied kernel/rootfs, and refuses rather than
|
|
21
|
+
* pretend — it never falls back to a weaker backend.
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
*/
|
|
25
|
+
import { spawn } from 'node:child_process';
|
|
26
|
+
import { existsSync } from 'node:fs';
|
|
27
|
+
import { fileURLToPath } from 'node:url';
|
|
28
|
+
import * as path from 'node:path';
|
|
29
|
+
import { log } from '../logger.js';
|
|
30
|
+
import { binaryOnPath } from '../binaryOnPath.js';
|
|
31
|
+
/**
|
|
32
|
+
* Build the Firecracker VM config. Pure and exported so the exact boot config
|
|
33
|
+
* — the one proven to boot a guest kernel on KVM — is asserted without a VM.
|
|
34
|
+
*
|
|
35
|
+
* The boot args are load-bearing: `root=/dev/vda rw` (the rootfs is the first
|
|
36
|
+
* virtio-blk device) and the kernel `ip=` directive that configures the guest's
|
|
37
|
+
* eth0 on the point-to-point tap link so its only reachable peer is the host.
|
|
38
|
+
*/
|
|
39
|
+
export function buildFirecrackerConfig(opts) {
|
|
40
|
+
const netmask = prefixToNetmask(opts.prefixLen);
|
|
41
|
+
const bootArgs = 'console=ttyS0 reboot=k panic=1 pci=off root=/dev/vda rw ' +
|
|
42
|
+
`ip=${opts.guestIp}::${opts.hostIp}:${netmask}::eth0:off`;
|
|
43
|
+
return {
|
|
44
|
+
'boot-source': { kernel_image_path: opts.kernelPath, boot_args: bootArgs },
|
|
45
|
+
drives: [
|
|
46
|
+
{
|
|
47
|
+
drive_id: 'rootfs',
|
|
48
|
+
path_on_host: opts.rootfsPath,
|
|
49
|
+
is_root_device: true,
|
|
50
|
+
is_read_only: false,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
'network-interfaces': [{ iface_id: 'eth0', host_dev_name: opts.tapDevice }],
|
|
54
|
+
'machine-config': { vcpu_count: opts.vcpus, mem_size_mib: opts.memMib },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** Dotted-quad netmask for a prefix length (IPv4). */
|
|
58
|
+
export function prefixToNetmask(prefix) {
|
|
59
|
+
const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
|
|
60
|
+
return [24, 16, 8, 0].map((s) => (mask >>> s) & 0xff).join('.');
|
|
61
|
+
}
|
|
62
|
+
/** Path to the validated launch script shipped with the CLI. */
|
|
63
|
+
function launchScriptPath() {
|
|
64
|
+
// dist layout: dist/lib/sandbox/firecracker.js → ../../../resources/…
|
|
65
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
66
|
+
return path.resolve(here, '../../../resources/sandbox/firecracker-launch.sh');
|
|
67
|
+
}
|
|
68
|
+
export class FirecrackerBackend {
|
|
69
|
+
name = 'firecracker';
|
|
70
|
+
opts;
|
|
71
|
+
env;
|
|
72
|
+
constructor(opts, env) {
|
|
73
|
+
this.opts = opts;
|
|
74
|
+
this.env = env;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Available only where a microVM can actually run: KVM present, the
|
|
78
|
+
* firecracker binary on PATH, and the operator's kernel + rootfs readable.
|
|
79
|
+
* Any of these missing → unavailable, and the caller refuses rather than
|
|
80
|
+
* downgrade (the honesty rule).
|
|
81
|
+
*/
|
|
82
|
+
async health() {
|
|
83
|
+
if (!existsSync('/dev/kvm')) {
|
|
84
|
+
return { available: false, detail: 'no /dev/kvm (needs a KVM host; nested-virt on Intel)' };
|
|
85
|
+
}
|
|
86
|
+
if (!existsSync(this.opts.kernelPath)) {
|
|
87
|
+
return { available: false, detail: `guest kernel not found: ${this.opts.kernelPath}` };
|
|
88
|
+
}
|
|
89
|
+
if (!existsSync(this.opts.rootfsPath)) {
|
|
90
|
+
return { available: false, detail: `guest rootfs not found: ${this.opts.rootfsPath}` };
|
|
91
|
+
}
|
|
92
|
+
const hasBinary = await binaryOnPath('firecracker');
|
|
93
|
+
if (!hasBinary) {
|
|
94
|
+
return { available: false, detail: 'firecracker binary not on PATH' };
|
|
95
|
+
}
|
|
96
|
+
return { available: true, detail: 'kvm + firecracker + kernel + rootfs present' };
|
|
97
|
+
}
|
|
98
|
+
async run(spec) {
|
|
99
|
+
// The launch script is the artifact validated on real KVM: it sets up the
|
|
100
|
+
// tap, installs the host-side default-deny egress firewall for the guest,
|
|
101
|
+
// boots the microVM with the config above, runs the agent command in the
|
|
102
|
+
// guest, and tears everything down. run() is a thin, faithful invoker of it
|
|
103
|
+
// so the shipped boot path is exactly the proven one.
|
|
104
|
+
const script = launchScriptPath();
|
|
105
|
+
if (!existsSync(script)) {
|
|
106
|
+
log.error(`firecracker launch script missing: ${script}`);
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
const args = [
|
|
110
|
+
script,
|
|
111
|
+
'--kernel', this.opts.kernelPath,
|
|
112
|
+
'--rootfs', this.opts.rootfsPath,
|
|
113
|
+
'--tap', this.opts.tapDevice,
|
|
114
|
+
'--guest-ip', this.opts.guestIp,
|
|
115
|
+
'--host-ip', this.opts.hostIp,
|
|
116
|
+
'--prefix', String(this.opts.prefixLen),
|
|
117
|
+
'--vcpus', String(this.opts.vcpus),
|
|
118
|
+
'--mem', String(this.opts.memMib),
|
|
119
|
+
'--allow', spec.allowCidrs.join(','),
|
|
120
|
+
'--', ...spec.command,
|
|
121
|
+
];
|
|
122
|
+
return new Promise((resolve) => {
|
|
123
|
+
const child = spawn('bash', args, {
|
|
124
|
+
stdio: 'inherit',
|
|
125
|
+
env: { ...process.env, ...this.env },
|
|
126
|
+
});
|
|
127
|
+
child.on('error', (err) => {
|
|
128
|
+
log.error(`firecracker launch failed: ${err.message}`);
|
|
129
|
+
resolve(127);
|
|
130
|
+
});
|
|
131
|
+
child.on('exit', (code, signal) => resolve(signal ? 128 : (code ?? 0)));
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=firecracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firecracker.js","sourceRoot":"","sources":["../../../src/lib/sandbox/firecracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox backend selection (LLD #63 §6).
|
|
3
|
+
*
|
|
4
|
+
* Picks the requested backend, or the best available one. The honesty rule:
|
|
5
|
+
* a backend whose `health()` is false is never silently swapped for a weaker
|
|
6
|
+
* one — the caller is told what is unavailable and why, and can decide.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { type FirecrackerOptions } from './firecracker.js';
|
|
11
|
+
import { OciBackend, type OciRuntime } from './oci.js';
|
|
12
|
+
import type { SandboxBackend } from './types.js';
|
|
13
|
+
export * from './types.js';
|
|
14
|
+
export { buildOciArgs, OciBackend } from './oci.js';
|
|
15
|
+
export { buildFirecrackerConfig, FirecrackerBackend } from './firecracker.js';
|
|
16
|
+
export type SandboxKind = 'oci' | 'firecracker';
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a container backend, preferring docker then podman. `env` holds the
|
|
19
|
+
* values the runtime will read for `--env NAME` references (proxy vars, keys).
|
|
20
|
+
*/
|
|
21
|
+
export declare function ociBackend(env: Record<string, string>, runtime?: OciRuntime): OciBackend;
|
|
22
|
+
/**
|
|
23
|
+
* Firecracker options from env, with defaults. The kernel + rootfs are
|
|
24
|
+
* operator-supplied (INTUTIC_FC_KERNEL / INTUTIC_FC_ROOTFS), like an OCI image
|
|
25
|
+
* is operator-supplied — the backend's `health()` refuses if they are missing.
|
|
26
|
+
*/
|
|
27
|
+
export declare function firecrackerOptionsFromEnv(env?: NodeJS.ProcessEnv): FirecrackerOptions;
|
|
28
|
+
/**
|
|
29
|
+
* Select a backend by kind. Both backends gate on their own `health()`; the
|
|
30
|
+
* caller refuses when a backend is unavailable rather than downgrading to a
|
|
31
|
+
* weaker one (the honesty rule, LLD #63 §6).
|
|
32
|
+
*/
|
|
33
|
+
export declare function selectBackend(kind: SandboxKind, env: Record<string, string>, runtime?: OciRuntime): SandboxBackend;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/sandbox/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE7E,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,aAAa,CAAA;AAE/C;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,UAAU,CAExF;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,kBAAkB,CAWlG;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,OAAO,CAAC,EAAE,UAAU,GACnB,cAAc,CAShB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox backend selection (LLD #63 §6).
|
|
3
|
+
*
|
|
4
|
+
* Picks the requested backend, or the best available one. The honesty rule:
|
|
5
|
+
* a backend whose `health()` is false is never silently swapped for a weaker
|
|
6
|
+
* one — the caller is told what is unavailable and why, and can decide.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { FirecrackerBackend } from './firecracker.js';
|
|
11
|
+
import { OciBackend } from './oci.js';
|
|
12
|
+
export * from './types.js';
|
|
13
|
+
export { buildOciArgs, OciBackend } from './oci.js';
|
|
14
|
+
export { buildFirecrackerConfig, FirecrackerBackend } from './firecracker.js';
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a container backend, preferring docker then podman. `env` holds the
|
|
17
|
+
* values the runtime will read for `--env NAME` references (proxy vars, keys).
|
|
18
|
+
*/
|
|
19
|
+
export function ociBackend(env, runtime) {
|
|
20
|
+
return new OciBackend(runtime ?? 'docker', env);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Firecracker options from env, with defaults. The kernel + rootfs are
|
|
24
|
+
* operator-supplied (INTUTIC_FC_KERNEL / INTUTIC_FC_ROOTFS), like an OCI image
|
|
25
|
+
* is operator-supplied — the backend's `health()` refuses if they are missing.
|
|
26
|
+
*/
|
|
27
|
+
export function firecrackerOptionsFromEnv(env = process.env) {
|
|
28
|
+
return {
|
|
29
|
+
kernelPath: env.INTUTIC_FC_KERNEL ?? '',
|
|
30
|
+
rootfsPath: env.INTUTIC_FC_ROOTFS ?? '',
|
|
31
|
+
tapDevice: env.INTUTIC_FC_TAP ?? 'tap-intutic',
|
|
32
|
+
guestIp: env.INTUTIC_FC_GUEST_IP ?? '172.16.0.2',
|
|
33
|
+
hostIp: env.INTUTIC_FC_HOST_IP ?? '172.16.0.1',
|
|
34
|
+
prefixLen: Number.parseInt(env.INTUTIC_FC_PREFIX ?? '30', 10),
|
|
35
|
+
vcpus: Number.parseInt(env.INTUTIC_FC_VCPUS ?? '1', 10),
|
|
36
|
+
memMib: Number.parseInt(env.INTUTIC_FC_MEM ?? '512', 10),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Select a backend by kind. Both backends gate on their own `health()`; the
|
|
41
|
+
* caller refuses when a backend is unavailable rather than downgrading to a
|
|
42
|
+
* weaker one (the honesty rule, LLD #63 §6).
|
|
43
|
+
*/
|
|
44
|
+
export function selectBackend(kind, env, runtime) {
|
|
45
|
+
switch (kind) {
|
|
46
|
+
case 'oci':
|
|
47
|
+
return ociBackend(env, runtime);
|
|
48
|
+
case 'firecracker':
|
|
49
|
+
return new FirecrackerBackend(firecrackerOptionsFromEnv(), env);
|
|
50
|
+
default:
|
|
51
|
+
throw new Error(`unknown sandbox backend '${kind}'`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/sandbox/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,kBAAkB,EAA2B,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EAAE,UAAU,EAAmB,MAAM,UAAU,CAAA;AAGtD,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAI7E;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,GAA2B,EAAE,OAAoB;IAC1E,OAAO,IAAI,UAAU,CAAC,OAAO,IAAI,QAAQ,EAAE,GAAG,CAAC,CAAA;AACjD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC5E,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,iBAAiB,IAAI,EAAE;QACvC,UAAU,EAAE,GAAG,CAAC,iBAAiB,IAAI,EAAE;QACvC,SAAS,EAAE,GAAG,CAAC,cAAc,IAAI,aAAa;QAC9C,OAAO,EAAE,GAAG,CAAC,mBAAmB,IAAI,YAAY;QAChD,MAAM,EAAE,GAAG,CAAC,kBAAkB,IAAI,YAAY;QAC9C,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,EAAE,EAAE,CAAC;QAC7D,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,gBAAgB,IAAI,GAAG,EAAE,EAAE,CAAC;QACvD,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,IAAI,KAAK,EAAE,EAAE,CAAC;KACzD,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAiB,EACjB,GAA2B,EAC3B,OAAoB;IAEpB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,KAAK;YACR,OAAO,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QACjC,KAAK,aAAa;YAChB,OAAO,IAAI,kBAAkB,CAAC,yBAAyB,EAAE,EAAE,GAAG,CAAC,CAAA;QACjE;YACE,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAc,GAAG,CAAC,CAAA;IAClE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OciBackend — a genuinely-isolating container sandbox (LLD #63 §6).
|
|
3
|
+
*
|
|
4
|
+
* The isolation envelope, and why each piece is here:
|
|
5
|
+
* --cap-drop=ALL start from zero capabilities
|
|
6
|
+
* --cap-add NET_ADMIN,NET_RAW the entrypoint needs them to install nft…
|
|
7
|
+
* --cap-add SETPCAP,SETUID,SETGID …and to drop those + switch user, after
|
|
8
|
+
* which the agent runs with an EMPTY cap set
|
|
9
|
+
* --security-opt no-new-privileges no setuid-root escalation
|
|
10
|
+
* --read-only + tmpfs immutable rootfs; scratch space in tmpfs
|
|
11
|
+
* --pids-limit/--memory/--cpus fork-bomb / resource-exhaustion bounds
|
|
12
|
+
* --add-host host.docker.internal:host-gateway reach the proxy on the host
|
|
13
|
+
* -v <workdir>:/work the project, the one writable mount
|
|
14
|
+
*
|
|
15
|
+
* The entrypoint (resources/sandbox/entrypoint.sh) then default-denies egress
|
|
16
|
+
* to everything except the proxy + DNS and drops privilege, so the agent cannot
|
|
17
|
+
* reach the network except through governance and cannot undo the firewall.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import type { SandboxBackend, SandboxHealth, SandboxSpec } from './types.js';
|
|
22
|
+
export type OciRuntime = 'docker' | 'podman';
|
|
23
|
+
/**
|
|
24
|
+
* Build the container runtime argv for a spec. Pure and exported so the
|
|
25
|
+
* envelope can be asserted without launching anything — the isolation flags are
|
|
26
|
+
* security-load-bearing and must not silently drift.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildOciArgs(runtime: OciRuntime, spec: SandboxSpec): string[];
|
|
29
|
+
export declare class OciBackend implements SandboxBackend {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
private readonly runtime;
|
|
32
|
+
/** Env values to hand the runtime process (referenced by name in argv). */
|
|
33
|
+
private readonly env;
|
|
34
|
+
constructor(runtime: OciRuntime, env: Record<string, string>);
|
|
35
|
+
health(): Promise<SandboxHealth>;
|
|
36
|
+
run(spec: SandboxSpec): Promise<number>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=oci.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oci.d.ts","sourceRoot":"","sources":["../../../src/lib/sandbox/oci.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE5E,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAE5C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,GAAG,MAAM,EAAE,CAoC7E;AAED,qBAAa,UAAW,YAAW,cAAc;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAY;IACpC,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAwB;gBAEhC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAMtD,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;IAgBhC,GAAG,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;CAuB9C"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OciBackend — a genuinely-isolating container sandbox (LLD #63 §6).
|
|
3
|
+
*
|
|
4
|
+
* The isolation envelope, and why each piece is here:
|
|
5
|
+
* --cap-drop=ALL start from zero capabilities
|
|
6
|
+
* --cap-add NET_ADMIN,NET_RAW the entrypoint needs them to install nft…
|
|
7
|
+
* --cap-add SETPCAP,SETUID,SETGID …and to drop those + switch user, after
|
|
8
|
+
* which the agent runs with an EMPTY cap set
|
|
9
|
+
* --security-opt no-new-privileges no setuid-root escalation
|
|
10
|
+
* --read-only + tmpfs immutable rootfs; scratch space in tmpfs
|
|
11
|
+
* --pids-limit/--memory/--cpus fork-bomb / resource-exhaustion bounds
|
|
12
|
+
* --add-host host.docker.internal:host-gateway reach the proxy on the host
|
|
13
|
+
* -v <workdir>:/work the project, the one writable mount
|
|
14
|
+
*
|
|
15
|
+
* The entrypoint (resources/sandbox/entrypoint.sh) then default-denies egress
|
|
16
|
+
* to everything except the proxy + DNS and drops privilege, so the agent cannot
|
|
17
|
+
* reach the network except through governance and cannot undo the firewall.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
import { spawn } from 'node:child_process';
|
|
22
|
+
import { log } from '../logger.js';
|
|
23
|
+
/**
|
|
24
|
+
* Build the container runtime argv for a spec. Pure and exported so the
|
|
25
|
+
* envelope can be asserted without launching anything — the isolation flags are
|
|
26
|
+
* security-load-bearing and must not silently drift.
|
|
27
|
+
*/
|
|
28
|
+
export function buildOciArgs(runtime, spec) {
|
|
29
|
+
const args = ['run', '--rm'];
|
|
30
|
+
// -i always (pipe stdin); -t only when we have a real terminal.
|
|
31
|
+
args.push(spec.tty ? '-it' : '-i');
|
|
32
|
+
// Capability envelope: drop everything, add back only what the entrypoint
|
|
33
|
+
// needs to install the firewall and drop privilege.
|
|
34
|
+
args.push('--cap-drop=ALL');
|
|
35
|
+
for (const cap of ['NET_ADMIN', 'NET_RAW', 'SETPCAP', 'SETUID', 'SETGID']) {
|
|
36
|
+
args.push(`--cap-add=${cap}`);
|
|
37
|
+
}
|
|
38
|
+
args.push('--security-opt=no-new-privileges');
|
|
39
|
+
// Immutable rootfs with writable scratch.
|
|
40
|
+
args.push('--read-only');
|
|
41
|
+
for (const t of ['/tmp', '/run', '/home/sandbox'])
|
|
42
|
+
args.push('--tmpfs', t);
|
|
43
|
+
// Resource bounds.
|
|
44
|
+
args.push(`--pids-limit=${spec.pidsLimit}`);
|
|
45
|
+
args.push(`--memory=${spec.memory}`);
|
|
46
|
+
args.push(`--cpus=${spec.cpus}`);
|
|
47
|
+
// Reach the proxy on the host.
|
|
48
|
+
args.push(`--add-host=${spec.proxyHostAlias}:host-gateway`);
|
|
49
|
+
// The project, read-write; nothing else from the host.
|
|
50
|
+
args.push('-v', `${spec.workdir}:/work`, '-w', '/work');
|
|
51
|
+
// Env by name — values come from the launcher's environment at spawn time, so
|
|
52
|
+
// secrets never land in argv.
|
|
53
|
+
for (const key of spec.envKeys)
|
|
54
|
+
args.push('--env', key);
|
|
55
|
+
args.push(spec.image);
|
|
56
|
+
// The entrypoint consumes a leading `--` then execs the rest.
|
|
57
|
+
args.push('--', ...spec.command);
|
|
58
|
+
return args;
|
|
59
|
+
}
|
|
60
|
+
export class OciBackend {
|
|
61
|
+
name;
|
|
62
|
+
runtime;
|
|
63
|
+
/** Env values to hand the runtime process (referenced by name in argv). */
|
|
64
|
+
env;
|
|
65
|
+
constructor(runtime, env) {
|
|
66
|
+
this.runtime = runtime;
|
|
67
|
+
this.name = runtime;
|
|
68
|
+
this.env = env;
|
|
69
|
+
}
|
|
70
|
+
async health() {
|
|
71
|
+
return new Promise((resolve) => {
|
|
72
|
+
const child = spawn(this.runtime, ['info', '--format', '{{.ServerVersion}}'], {
|
|
73
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
74
|
+
});
|
|
75
|
+
child.on('error', () => resolve({ available: false, detail: `${this.runtime} not found on PATH` }));
|
|
76
|
+
child.on('exit', (code) => code === 0
|
|
77
|
+
? resolve({ available: true, detail: `${this.runtime} daemon reachable` })
|
|
78
|
+
: resolve({ available: false, detail: `${this.runtime} daemon not reachable` }));
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async run(spec) {
|
|
82
|
+
const args = buildOciArgs(this.runtime, spec);
|
|
83
|
+
log.dim(`sandbox: ${this.runtime} ${args.slice(0, 12).join(' ')} …`);
|
|
84
|
+
return new Promise((resolve) => {
|
|
85
|
+
const child = spawn(this.runtime, args, {
|
|
86
|
+
stdio: 'inherit',
|
|
87
|
+
// Values for the `--env NAME` references live here, not in argv.
|
|
88
|
+
env: { ...process.env, ...this.env },
|
|
89
|
+
});
|
|
90
|
+
child.on('error', (err) => {
|
|
91
|
+
if (err.code === 'ENOENT') {
|
|
92
|
+
log.error(`Sandbox runtime '${this.runtime}' not found. Install Docker or Podman.`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
log.error(`Sandbox failed to start: ${err.message}`);
|
|
96
|
+
}
|
|
97
|
+
resolve(127);
|
|
98
|
+
});
|
|
99
|
+
child.on('exit', (code, signal) => {
|
|
100
|
+
if (signal)
|
|
101
|
+
resolve(128);
|
|
102
|
+
else
|
|
103
|
+
resolve(code ?? 0);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=oci.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oci.js","sourceRoot":"","sources":["../../../src/lib/sandbox/oci.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox runtime abstraction (LLD #63 §6).
|
|
3
|
+
*
|
|
4
|
+
* A `SandboxBackend` launches an agent command inside an isolated runtime whose
|
|
5
|
+
* *only* egress is the governing proxy — unifying "isolate the process" with
|
|
6
|
+
* "force traffic through governance". The container backend ships today; the
|
|
7
|
+
* Firecracker microVM backend implements the same interface (Increment 4).
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
/** What to run, and the isolation envelope to run it in. */
|
|
12
|
+
export interface SandboxSpec {
|
|
13
|
+
/** The agent command + args, e.g. ['claude'] or ['python', 'agent.py']. */
|
|
14
|
+
command: string[];
|
|
15
|
+
/** Host directory bind-mounted read-write at /work (the project). */
|
|
16
|
+
workdir: string;
|
|
17
|
+
/** Container image. Must contain the agent + nftables + capsh. */
|
|
18
|
+
image: string;
|
|
19
|
+
/**
|
|
20
|
+
* Environment for the sandboxed process, by name. Values are read from the
|
|
21
|
+
* launcher's own environment at spawn time and referenced by name on the
|
|
22
|
+
* command line, so secrets (API keys) never appear in argv / `docker inspect`.
|
|
23
|
+
*/
|
|
24
|
+
envKeys: string[];
|
|
25
|
+
/** Hostname the sandbox reaches the proxy at (mapped to the host gateway). */
|
|
26
|
+
proxyHostAlias: string;
|
|
27
|
+
/** Extra destination CIDRs the sandbox may reach, beyond the proxy + DNS. */
|
|
28
|
+
allowCidrs: string[];
|
|
29
|
+
/** Hard resource caps. */
|
|
30
|
+
memory: string;
|
|
31
|
+
cpus: string;
|
|
32
|
+
pidsLimit: number;
|
|
33
|
+
/** Allocate a TTY (interactive agents). */
|
|
34
|
+
tty: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Health of a backend on this host. */
|
|
37
|
+
export interface SandboxHealth {
|
|
38
|
+
available: boolean;
|
|
39
|
+
detail: string;
|
|
40
|
+
}
|
|
41
|
+
export interface SandboxBackend {
|
|
42
|
+
readonly name: string;
|
|
43
|
+
/** Whether this backend can run here (e.g. docker reachable, KVM present). */
|
|
44
|
+
health(): Promise<SandboxHealth>;
|
|
45
|
+
/** Launch the spec; resolves with the process exit code. */
|
|
46
|
+
run(spec: SandboxSpec): Promise<number>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/sandbox/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,CAAA;IACtB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,2CAA2C;IAC3C,GAAG,EAAE,OAAO,CAAA;CACb;AAED,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,8EAA8E;IAC9E,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC,CAAA;IAChC,4DAA4D;IAC5D,GAAG,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACxC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox runtime abstraction (LLD #63 §6).
|
|
3
|
+
*
|
|
4
|
+
* A `SandboxBackend` launches an agent command inside an isolated runtime whose
|
|
5
|
+
* *only* egress is the governing proxy — unifying "isolate the process" with
|
|
6
|
+
* "force traffic through governance". The container backend ships today; the
|
|
7
|
+
* Firecracker microVM backend implements the same interface (Increment 4).
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/sandbox/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export type SopRiskTier = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
|
2
|
+
export interface ParsedSopFile {
|
|
3
|
+
/** From a `title:` front-matter key, else the file's first `# ` heading, else `null` — the caller falls back to the file name. */
|
|
4
|
+
title: string | null;
|
|
5
|
+
/** From a `risk_tier:` key, case-insensitively; `null` if unstated or unrecognised — never guessed. */
|
|
6
|
+
riskTier: SopRiskTier | null;
|
|
7
|
+
/** From a `version:` key; `null` if unstated. */
|
|
8
|
+
version: string | null;
|
|
9
|
+
/**
|
|
10
|
+
* From a `content_hash:` key — `intutic sops pull`'s own dirty-check
|
|
11
|
+
* marker, recording the body hash at the moment it wrote the file. `null`
|
|
12
|
+
* for a file `pull` never wrote (hand-authored, or pushed but not pulled).
|
|
13
|
+
*/
|
|
14
|
+
contentHash: string | null;
|
|
15
|
+
/** Everything after the front-matter fence, or the whole trimmed input when there is none. */
|
|
16
|
+
body: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function parseSopFile(raw: string): ParsedSopFile;
|
|
19
|
+
/**
|
|
20
|
+
* Render a pulled SOP back into a front-matter-carrying file, with
|
|
21
|
+
* `content_hash:` recording `sha256(body)` at write time — the marker
|
|
22
|
+
* `runSopsPull` compares against on a later pull to tell "the DB changed
|
|
23
|
+
* upstream" (safe to overwrite) from "a human hand-edited this file since
|
|
24
|
+
* the last pull" (refuse without `--force`).
|
|
25
|
+
*/
|
|
26
|
+
export declare function renderSopFile(sop: {
|
|
27
|
+
title: string;
|
|
28
|
+
riskTier: string;
|
|
29
|
+
version: string;
|
|
30
|
+
body: string;
|
|
31
|
+
}): string;
|
|
32
|
+
/** `Deploy Checklist` / `deploy checklist!!` → `deploy-checklist`. */
|
|
33
|
+
export declare function slugifyTitle(title: string): string;
|
|
34
|
+
/** `postgres-migration` → `Postgres Migration`; `deploy_checklist.md` → `Deploy Checklist`. */
|
|
35
|
+
export declare function titleFromFileName(fileName: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Add `intutic sops pull`'s `content_hash:` marker to a file that already
|
|
38
|
+
* carries its own front matter — a projected guardrail, whose fence holds
|
|
39
|
+
* the enforcing keys the proxy reads (LLD #71, Wave 9).
|
|
40
|
+
*
|
|
41
|
+
* Not `renderSopFile`: that wraps a second fence around the text, and the
|
|
42
|
+
* proxy reads only the first, so the enforcing keys would become body prose
|
|
43
|
+
* and the rule would load, be listed, and never fire. The marker goes INSIDE
|
|
44
|
+
* the existing fence, as the last line before it closes; the hash is over
|
|
45
|
+
* what `parseSopFile` will read back as `body`, so the dirty check is the
|
|
46
|
+
* same one `sops pull` runs. A file with no fence gets one holding only the
|
|
47
|
+
* marker. Unknown keys are inert to the proxy, so enforcement is unchanged.
|
|
48
|
+
*/
|
|
49
|
+
export declare function withContentHash(raw: string): string;
|
|
50
|
+
//# sourceMappingURL=sopFrontMatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sopFrontMatter.d.ts","sourceRoot":"","sources":["../../src/lib/sopFrontMatter.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAA;AAIhE,MAAM,WAAW,aAAa;IAC5B,kIAAkI;IAClI,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,uGAAuG;IACvG,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAA;IAC5B,iDAAiD;IACjD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB;;;;OAIG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,8FAA8F;IAC9F,IAAI,EAAE,MAAM,CAAA;CACb;AAaD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAkCvD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,MAAM,CAaT;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED,+FAA+F;AAC/F,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAcnD"}
|