Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
505 changes: 10 additions & 495 deletions ci/source-shape-test-budget.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ Isolated `node:22-trixie-slim` containers globally installed the reviewed OpenCl
Invalid state: any reviewed archive install can run package-controlled install hooks, a package other than an exact allowlisted OpenClaw version receives an explicit lifecycle invocation, or the allowed manifest command/path changes without review.
Source boundary: the five Docker install transactions, `installOpenClawMessagingPlugins`, and `ci/reviewed-npm-lifecycle-allowlist.json`.
Source-fix constraint: lifecycle suppression must remain caller-controlled even while OpenClaw's plugin installer independently applies the same policy; do not replace the fixed postinstall command with `npm rebuild`, `npm run` against an unverified package spec, or a blanket script enablement.
Regression tests: `test/openclaw-lifecycle-policy.test.ts` pins the complete reviewed package set and the two exact exceptions; the integrity-pin base and plugin-install suites, `test/fetch-guard-patch-regression.test.ts`, and `test/messaging-build-applier.test.ts` pin script suppression and the fixed postinstall command at the execution boundaries.
Regression tests: the integrity-pin base and plugin-install suites, `test/fetch-guard-patch-regression.test.ts`, and `test/messaging-build-applier.test.ts` exercise script suppression and the fixed postinstall command at the execution boundaries.
Removal condition: re-audit manifests, shrinkwrap `hasInstallScript` entries, and native prebuild coverage on every OpenClaw/plugin bump; remove an exception when the reviewed package no longer needs it, and never carry an exception to a new version implicitly.

#### Messaging Plugin Registry Provenance Boundary
Expand Down
69 changes: 27 additions & 42 deletions src/lib/actions/sandbox/mcp-bridge-input-validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@ import {
} from "./mcp-bridge";
import childVisibleCredentialManifest from "./openshell-child-visible-credentials.v0.0.101.json";

const CHILD_VISIBLE_CREDENTIAL_CASES = [
{
names: childVisibleCredentialManifest.rawChildValueKeys,
error: /materialized as a raw child-process value|preserve the host-only credential boundary/,
},
{
names: childVisibleCredentialManifest.rewrittenChildValueKeys,
error: /rewritten by OpenShell's Google Cloud metadata compatibility path/,
},
].flatMap(({ names, error }) =>
names.flatMap((name) => [
{ name, form: "--env NAME", envArgs: ["--env", name], error },
{ name, form: "-e NAME", envArgs: ["-e", name], error },
{ name, form: "--env=NAME", envArgs: [`--env=${name}`], error },
]),
);


describe("MCP CLI input validation", () => {
it("parses server, URL, and env references", () => {
const parsed = parseMcpAddArgs([
Expand Down Expand Up @@ -119,53 +137,20 @@ describe("MCP CLI input validation", () => {
}
});

// source-shape-contract: compatibility -- Pinned OpenShell child-visible keys must drive credential rejection through every MCP boundary
it("rejects OpenShell child-environment compatibility keys as MCP credentials", () => {
for (const name of childVisibleCredentialManifest.rawChildValueKeys) {
it.each(CHILD_VISIBLE_CREDENTIAL_CASES)(
"rejects $name from $form at every MCP credential boundary",
({ name, envArgs, error }) => {
expect(() =>
parseMcpAddArgs(["github", "--url", "https://mcp.example.test/mcp", "--env", name]),
).toThrow(/materialized as a raw child-process value/);
expect(() => resolveCredentialEnv([{ name, value: "host-only-secret" }])).toThrow(
/preserve the host-only credential boundary/,
);
parseMcpAddArgs(["github", "--url", "https://mcp.example.test/mcp", ...envArgs]),
).toThrow(error);
expect(() => resolveCredentialEnv([{ name, value: "host-only-secret" }])).toThrow(error);
expect(() =>
buildMcpBridgeProviderArgs("create", "provider", [{ name }], {
[name]: "host-only-secret",
}),
).toThrow(/materialized as a raw child-process value/);
}

for (const name of childVisibleCredentialManifest.rewrittenChildValueKeys) {
expect(() =>
parseMcpAddArgs(["github", "--url", "https://mcp.example.test/mcp", "--env", name]),
).toThrow(/rewritten by OpenShell's Google Cloud metadata compatibility path/);
}
});

// source-shape-contract: compatibility -- Host subprocess controls must stay synchronized with the pinned OpenShell child environment boundary
it("rejects host subprocess control and allowlist names as MCP credentials", () => {
for (const name of SUBPROCESS_ENV_ALLOWED_NAMES) {
expect(childVisibleCredentialManifest.runtimeControlKeys).toContain(name);
}
for (const prefix of SUBPROCESS_ENV_ALLOWED_PREFIXES) {
expect(childVisibleCredentialManifest.runtimeControlPrefixes).toContain(prefix);
}
for (const name of [
"PATH",
"HOME",
"HTTP_PROXY",
"SSL_CERT_FILE",
"KUBECONFIG",
"LC_ALL",
"XDG_CONFIG_HOME",
"OPENSHELL_GATEWAY",
"GRPC_TRACE",
]) {
expect(() =>
parseMcpAddArgs(["github", "--url", "https://mcp.example.test/mcp", "--env", name]),
).toThrow(/reserved for host subprocess control/);
}
});
).toThrow(error);
},
);

it("rejects sandbox runtime-control names as MCP credentials", () => {
for (const name of [
Expand Down
112 changes: 0 additions & 112 deletions src/lib/agent/base-image-hermes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,118 +40,6 @@ describe("agent base image provisioning", () => {
});
});

// source-shape-contract: security -- Ordinary onboarding must use the pinned Hermes base image and check installed dependency versions after messaging package installation.
it("requires the pinned Hermes base image and checks installed dependency versions after messaging package installation (#8328)", () => {
const dockerfilePath = path.resolve(import.meta.dirname, "../../../agents/hermes/Dockerfile");
const dockerfile = fs.readFileSync(dockerfilePath, "utf8");
const trackedRef = dockerfile.match(
/^ARG BASE_IMAGE=(ghcr\.io\/nvidia\/nemoclaw\/hermes-sandbox-base@(sha256:[0-9a-f]{64}))$/m,
);
expect(trackedRef).not.toBeNull();
expect(trackedRef?.[1]).toBe(
"ghcr.io/nvidia/nemoclaw/hermes-sandbox-base@sha256:ffafa4dd1d8d5a802ae4fc4005b51e1accfa5e782e47de736a0d8d8bf2c83837",
);

const messagingInstallIndex = dockerfile.indexOf("RUN unset SSL_CERT_FILE REQUESTS_CA_BUNDLE");
const managedInstallIndex = dockerfile.indexOf(
"RUN --network=none --mount=from=hermes-managed-teams-wheels",
);
const installLayer = dockerRunCommandBetween(
dockerfile,
"RUN --network=none --mount=from=hermes-managed-teams-wheels",
"WORKDIR /sandbox",
).replace(/\s+/gu, " ");
const versionGuard =
"/opt/hermes/.venv/bin/python -I -c \"from importlib.metadata import version; expected = {'aiohttp': '3.14.3', 'cryptography': '50.0.0'}; actual = {name: version(name) for name in expected}; assert actual == expected, actual\"";
const versionGuardIndex = installLayer.indexOf(versionGuard);
const finalConditionalEnd = [...installLayer.matchAll(/\bfi\b/gu)].at(-1)?.index ?? -1;

expect(messagingInstallIndex).toBeGreaterThanOrEqual(0);
expect(managedInstallIndex).toBeGreaterThan(messagingInstallIndex);
expect(versionGuardIndex).toBeGreaterThan(finalConditionalEnd);
expect(installLayer).not.toContain("'aiohttp': '3.14.1'");
expect(installLayer).not.toContain("'cryptography': '48.0.1'");

withMockedDocker(({ ensureAgentBaseImage, resolveSandboxBaseImageMock }) => {
resolveSandboxBaseImageMock.mockReturnValue({
ref: trackedRef?.[1],
digest: trackedRef?.[2],
source: "source-sha",
glibcVersion: "2.41",
});

expect(ensureAgentBaseImage(makeAgent({ dockerfilePath }))).toEqual({
imageTag: trackedRef?.[1],
built: false,
});
expect(resolveSandboxBaseImageMock).toHaveBeenCalledWith(
expect.objectContaining({
pinnedRemoteRef: trackedRef?.[1],
preferPinnedRemoteRef: true,
}),
);

const platformDigest =
"sha256:c0c149ed03b3e8fcd3e395558b22e871cd27c9966ea6faf04c0d2b94d0a821b9";
const platformDigestRef = `ghcr.io/nvidia/nemoclaw/hermes-sandbox-base@${platformDigest}`;
resolveSandboxBaseImageMock.mockReturnValue({
ref: platformDigestRef,
digest: platformDigest,
source: "pinned",
pinnedRemoteRef: trackedRef?.[1],
glibcVersion: "2.41",
});
expect(ensureAgentBaseImage(makeAgent({ dockerfilePath }))).toEqual({
imageTag: platformDigestRef,
built: false,
});

const wrongNamespaceRef = `ghcr.io/nvidia/nemoclaw/other-hermes-base@${platformDigest}`;
resolveSandboxBaseImageMock.mockReturnValue({
ref: wrongNamespaceRef,
digest: platformDigest,
source: "pinned",
pinnedRemoteRef: trackedRef?.[1],
glibcVersion: "2.41",
});
expect(() => ensureAgentBaseImage(makeAgent({ dockerfilePath }))).toThrow(
"Hermes final image does not accept base image ref",
);

resolveSandboxBaseImageMock.mockReturnValue({
ref: platformDigestRef,
digest: platformDigest,
source: "latest",
glibcVersion: "2.41",
});
expect(() => ensureAgentBaseImage(makeAgent({ dockerfilePath }))).toThrow(
"Hermes final image does not accept base image ref",
);

resolveSandboxBaseImageMock.mockReturnValue({
ref: platformDigestRef,
digest: platformDigest,
source: "pinned",
pinnedRemoteRef: `ghcr.io/nvidia/nemoclaw/hermes-sandbox-base@sha256:${"2".repeat(64)}`,
glibcVersion: "2.41",
});
expect(() => ensureAgentBaseImage(makeAgent({ dockerfilePath }))).toThrow(
"Hermes final image does not accept base image ref",
);

const differentRef = `ghcr.io/nvidia/nemoclaw/hermes-sandbox-base@sha256:${"0".repeat(64)}`;
resolveSandboxBaseImageMock.mockReturnValue({
ref: differentRef,
digest: `sha256:${"0".repeat(64)}`,
source: "source-sha",
glibcVersion: "2.41",
});
expect(() => ensureAgentBaseImage(makeAgent({ dockerfilePath }))).toThrow(
"Hermes final image does not accept base image ref",
);
});
});

it("fails before candidate resolution when the Hermes final Dockerfile is unreadable", () => {
withMockedDocker(({ ensureAgentBaseImage, resolveSandboxBaseImageMock }) => {
expect(() =>
Expand Down
19 changes: 0 additions & 19 deletions src/lib/agent/state-directory-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,25 +144,6 @@ describe("agent state directory contract", () => {
).toEqual(testCase.expectedMutablePaths);
});

// source-shape-contract: security -- Generated image plans must match the reviewed AgentDefinition projection
it("keeps generated image plans equal to their AgentDefinition projections (#8006)", () => {
const imagePlanAgents = listAgents().filter(
(agentName) => loadAgent(agentName).stateLockPlanInImage,
);
for (const agentName of imagePlanAgents) {
const generated = JSON.parse(
fs.readFileSync(
path.join(process.cwd(), "agents", agentName, "state-lock-plan.json"),
"utf8",
),
) as Record<string, unknown>;
const { $comment, ...plan } = generated;

expect(typeof $comment).toBe("string");
expect(plan).toEqual(loadAgent(agentName).stateLockPlan);
}
});

it.each([
[{ state_dirs: "state" }, /state_dirs.*array/],
[{ state_dirs: ["../state"] }, /canonical relative path/],
Expand Down
6 changes: 3 additions & 3 deletions src/lib/inference/nvidia-featured-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export const NVIDIA_FEATURED_MODELS_URL =
"https://assets.ngc.nvidia.com/products/api-catalog/featured-models.json";
// NVIDIA Endpoints retirement contract: the public featured feed and
// authenticated /models catalog can lag a runtime retirement. The repository
// authority is CLOUD_MODEL_OPTIONS plus the provider-boundary assertion in
// test/inference-options-docs.test.ts, which keeps independently available
// Hermes Provider models separate from NVIDIA Endpoints choices. Keep entries
// authority is CLOUD_MODEL_OPTIONS. nvidia-featured-models.test.ts verifies
// the featured-feed filter, and config.test.ts verifies that retired model IDs
// remain absent from NVIDIA Endpoints choices. Keep entries
// in this policy deny-list until a deliberate product change confirms that the
// NVIDIA chat-completions route is available again or names a live successor.
const RETIRED_NVIDIA_FEATURED_MODEL_IDS = new Set([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,6 @@ import {
} from "./compatible-endpoint-gateway-route";

describe("compatible endpoint gateway routing", () => {
// source-shape-contract: compatibility -- Bundled loopback routing must match the shipped host-gateway policy ports
it("matches the bundled local-inference host-gateway ports (#5744)", () => {
const policyPath = path.resolve(
import.meta.dirname,
"../../../../nemoclaw-blueprint/policies/presets/local-inference.yaml",
);
const policy = YAML.parse(fs.readFileSync(policyPath, "utf8"));
const endpoints: Array<{ host?: string; port?: number }> =
policy.network_policies.local_inference.endpoints;
const hostGatewayPorts = endpoints
.filter(({ host }) => host === "host.openshell.internal")
.map(({ port }) => port)
.sort((left, right) => (left ?? 0) - (right ?? 0));

expect(hostGatewayPorts).toEqual(
[...BUNDLED_LOCAL_INFERENCE_GATEWAY_PORTS].sort((left, right) => left - right),
);
});

it("rewrites exact HTTP loopback hosts on bundled local-inference ports (#5744)", () => {
for (const host of ["localhost", "127.0.0.1", "[::1]"]) {
for (const port of COMPATIBLE_ENDPOINT_GATEWAY_PORTS) {
Expand Down
4 changes: 1 addition & 3 deletions src/lib/onboard/managed-bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,7 @@ This is executable, bounded groundwork rather than an untested placeholder.
failure rollback for OpenClaw, Hermes, and LangChain Deep Agents Code through an
MXC-named fake driver. `runtime-provider-contract.test.ts` verifies the
production Docker registration and an MXC-style bootstrap surface through the
same provider bundle contract. `runtime-provider-source-shape.test.ts`
inventories the protocol, provider, and image-packaging surfaces and proves that
ordinary onboarding does not select managed bootstrap.
same provider bundle contract.

The native entrypoint and composed managed-bootstrap image runtime are compiled
and packaged in every managed agent image. Internal Docker qualification and
Expand Down
51 changes: 0 additions & 51 deletions src/lib/onboard/managed-startup-profile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,57 +467,6 @@ describe("managed startup profile", () => {
).toThrow(/not supported/);
});

// source-shape-contract: compatibility -- Every shipped Docker build input must map to versioned startup intent or a declared build-only exclusion
it("classifies every stock Docker ARG as startup-affordance or deliberate exclusion", () => {
for (const agent of MANAGED_STARTUP_AGENTS) {
const classified = new Set([
...MANAGED_STARTUP_PROFILE_AFFORDANCE_INVENTORY[agent].map(({ input }) => input),
...MANAGED_STARTUP_PROFILE_EXCLUDED_DOCKER_INPUTS[agent].map(({ input }) => input),
]);
expect([...STOCK_DOCKER_ARGS[agent]].filter((input) => !classified.has(input))).toEqual([]);
}
});

// source-shape-contract: compatibility -- Every centralized agent runtime input must map to versioned startup intent or a typed downstream owner
it("classifies every centralized runtime input as profile intent or an explicit deferral", () => {
expect([...STOCK_RUNTIME_INPUTS].sort()).toEqual(
Object.keys(STOCK_RUNTIME_INPUT_AGENTS).sort(),
);
const missing = Object.entries(STOCK_RUNTIME_INPUT_AGENTS).flatMap(([input, agents]) =>
agents
.filter(
(agent) =>
!new Set([
...MANAGED_STARTUP_PROFILE_AFFORDANCE_INVENTORY[agent].map(
({ input: profileInput }) => profileInput,
),
...MANAGED_STARTUP_PROFILE_DEFERRED_RUNTIME_INPUTS[agent].map(
({ input: deferredInput }) => deferredInput,
),
]).has(input),
)
.map((agent) => `${agent}:${input}`),
);
expect(missing).toEqual([]);

const openClawAutoPairInputs = MANAGED_STARTUP_PROFILE_DEFERRED_RUNTIME_INPUTS.openclaw.filter(
({ input }) => input.startsWith("NEMOCLAW_AUTO_PAIR_"),
);
expect([...OPENCLAW_AUTO_PAIR_CONSUMER_INPUTS].sort()).toEqual(
openClawAutoPairInputs.map(({ input }) => input).sort(),
);
expect(
Object.fromEntries(openClawAutoPairInputs.map(({ admission, input }) => [input, admission])),
).toEqual({
NEMOCLAW_AUTO_PAIR_DEADLINE_SECS: "managed-launch-forwarded",
NEMOCLAW_AUTO_PAIR_FAST_DEADLINE_SECS: "managed-launch-forwarded",
NEMOCLAW_AUTO_PAIR_FAST_REENTRY_INTERVAL_SECS: "managed-launch-forwarded",
NEMOCLAW_AUTO_PAIR_FAST_REENTRY_POLLS: "managed-launch-forwarded",
NEMOCLAW_AUTO_PAIR_RUN_TIMEOUT_SECS: "managed-launch-forwarded",
NEMOCLAW_AUTO_PAIR_SLOW_INTERVAL_SECS: "managed-launch-forwarded",
});
});

it("records generic cross-agent emissions as cleanup obligations, not supported semantics", () => {
expect(MANAGED_STARTUP_RUNTIME_CLEANUP_OBLIGATIONS).toHaveLength(2);
for (const obligation of MANAGED_STARTUP_RUNTIME_CLEANUP_OBLIGATIONS) {
Expand Down
Loading
Loading