Skip to content
Closed
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
68 changes: 68 additions & 0 deletions .github/workflows/managed-images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,24 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}
persist-credentials: false

- name: Make reviewed runtime bundle files group-writable
shell: bash
run: |
set -euo pipefail
runtime_bundle_files=(
tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/managed-startup-image-runtime.bundle
tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/mcp-tool-discovery/BUNDLED_PACKAGES.json
tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/mcp-tool-discovery/THIRD_PARTY_LICENSES.txt
tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/mcp-tool-discovery/mcp-tool-discovery.bundle
Comment thread
coderabbitai[bot] marked this conversation as resolved.
)
for path in "${runtime_bundle_files[@]}"; do
if [[ ! -f "$path" || -L "$path" ]]; then
printf 'ERROR: reviewed runtime bundle input must be a regular non-symlink: %s\n' "$path" >&2
exit 1
fi
done
chmod 0664 "${runtime_bundle_files[@]}"

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0

Expand Down Expand Up @@ -190,6 +208,56 @@ jobs:
provenance: false
sbom: false

- name: Reject a symlinked runtime directory during image assembly
if: ${{ matrix.agent == 'langchain-deepagents-code' }}
shell: bash
env:
BASE_REFERENCE: ${{ steps.base.outputs.ref }}
DOCKERFILE: ${{ matrix.dockerfile }}
run: |
set -euo pipefail
probe_dockerfile="$RUNNER_TEMP/runtime-directory-symlink.Dockerfile"
probe_log="$RUNNER_TEMP/runtime-directory-symlink.log"
{
cat <<'PROBE_HEADER'
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
USER root
COPY --chown=0:0 --chmod=0444 tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/managed-startup-image-runtime.bundle /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs
COPY --chown=0:0 --chmod=0444 tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/mcp-tool-discovery/BUNDLED_PACKAGES.json /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime/BUNDLED_PACKAGES.json
COPY --chown=0:0 --chmod=0444 tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/mcp-tool-discovery/THIRD_PARTY_LICENSES.txt /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime/THIRD_PARTY_LICENSES.txt
COPY --chown=0:0 --chmod=0444 tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/mcp-tool-discovery/mcp-tool-discovery.bundle /usr/local/lib/nemoclaw/mcp-tool-discovery-runtime/mcp-tool-discovery.mjs
RUN rm -rf /run/nemoclaw \
&& ln -s /tmp /run/nemoclaw
PROBE_HEADER
awk '
/^RUN managed_runtime_assertion_failed\(\)/ { copying = 1 }
copying { print }
copying && /managed_runtime_assertion_failed runtime-directory-metadata-0:0:755 \/run\/nemoclaw$/ { exit }
' "$DOCKERFILE"
} > "$probe_dockerfile"

if [ "$(grep -c '^RUN managed_runtime_assertion_failed()' "$probe_dockerfile")" -ne 1 ]; then
echo "ERROR: could not extract one managed runtime assertion from $DOCKERFILE." >&2
exit 1
fi
if docker buildx build \
--platform linux/amd64 \
--build-arg "BASE_IMAGE=${BASE_REFERENCE}" \
--progress plain \
--file "$probe_dockerfile" \
. > "$probe_log" 2>&1; then
echo "ERROR: image assembly accepted a symlinked /run/nemoclaw directory." >&2
exit 1
fi
if ! grep -Fq \
'ERROR: managed image assertion failed: runtime-directory-non-symlink path=/run/nemoclaw' \
"$probe_log"; then
tail -80 "$probe_log" >&2
echo "ERROR: image assembly failed without the runtime-directory-non-symlink diagnostic." >&2
exit 1
fi

- name: Validate exact PR managed image contract
id: contract
shell: bash
Expand Down
17 changes: 10 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -1525,13 +1525,16 @@ RUN managed_runtime_assertion_failed() { \
&& { chown root:root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed owner-root-root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \
&& { chmod 0444 /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed mode-0444 /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \
&& { test "$(stat -c '%u:%g:%a' /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null)" = '0:0:444' || managed_runtime_assertion_failed metadata-0:0:444 /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \
&& test -f /usr/local/bin/nemoclaw-managed-bootstrap \
&& test ! -L /usr/local/bin/nemoclaw-managed-bootstrap \
&& test "$(stat -c '%u:%g:%a' /usr/local/bin/nemoclaw-managed-bootstrap)" = '0:0:755' \
&& test -f /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh \
&& test ! -L /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh \
&& test "$(stat -c '%u:%g:%a' /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh)" = '0:0:444' \
&& install -d -o root -g root -m 0755 /run/nemoclaw
&& { test -f /usr/local/bin/nemoclaw-managed-bootstrap || managed_runtime_assertion_failed managed-bootstrap-regular-file /usr/local/bin/nemoclaw-managed-bootstrap; } \
&& { test ! -L /usr/local/bin/nemoclaw-managed-bootstrap || managed_runtime_assertion_failed managed-bootstrap-non-symlink /usr/local/bin/nemoclaw-managed-bootstrap; } \
&& { test "$(stat -c '%u:%g:%a' /usr/local/bin/nemoclaw-managed-bootstrap)" = '0:0:755' || managed_runtime_assertion_failed managed-bootstrap-metadata-0:0:755 /usr/local/bin/nemoclaw-managed-bootstrap; } \
&& { test -f /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh || managed_runtime_assertion_failed managed-bootstrap-trampoline-regular-file /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh; } \
&& { test ! -L /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh || managed_runtime_assertion_failed managed-bootstrap-trampoline-non-symlink /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh; } \
&& { test "$(stat -c '%u:%g:%a' /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh)" = '0:0:444' || managed_runtime_assertion_failed managed-bootstrap-trampoline-metadata-0:0:444 /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh; } \
&& { install -d -o root -g root -m 0755 /run/nemoclaw || managed_runtime_assertion_failed runtime-directory-create /run/nemoclaw; } \
&& { test -d /run/nemoclaw || managed_runtime_assertion_failed runtime-directory /run/nemoclaw; } \
&& { test ! -L /run/nemoclaw || managed_runtime_assertion_failed runtime-directory-non-symlink /run/nemoclaw; } \
&& { test "$(stat -c '%u:%g:%a' /run/nemoclaw 2>/dev/null)" = '0:0:755' || managed_runtime_assertion_failed runtime-directory-metadata-0:0:755 /run/nemoclaw; }

# Copy startup script and shared sandbox initialisation library.
RUN chmod 755 /usr/local/bin/nemoclaw-start /usr/local/bin/nemoclaw-codex-acp \
Expand Down
17 changes: 10 additions & 7 deletions agents/hermes/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -387,13 +387,16 @@ RUN managed_runtime_assertion_failed() { \
&& { chown root:root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed owner-root-root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \
&& { chmod 0444 /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed mode-0444 /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \
&& { test "$(stat -c '%u:%g:%a' /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null)" = '0:0:444' || managed_runtime_assertion_failed metadata-0:0:444 /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \
&& test -f /usr/local/bin/nemoclaw-managed-bootstrap \
&& test ! -L /usr/local/bin/nemoclaw-managed-bootstrap \
&& test "$(stat -c '%u:%g:%a' /usr/local/bin/nemoclaw-managed-bootstrap)" = '0:0:755' \
&& test -f /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh \
&& test ! -L /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh \
&& test "$(stat -c '%u:%g:%a' /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh)" = '0:0:444' \
&& install -d -o root -g root -m 0755 /run/nemoclaw
&& { test -f /usr/local/bin/nemoclaw-managed-bootstrap || managed_runtime_assertion_failed managed-bootstrap-regular-file /usr/local/bin/nemoclaw-managed-bootstrap; } \
&& { test ! -L /usr/local/bin/nemoclaw-managed-bootstrap || managed_runtime_assertion_failed managed-bootstrap-non-symlink /usr/local/bin/nemoclaw-managed-bootstrap; } \
&& { test "$(stat -c '%u:%g:%a' /usr/local/bin/nemoclaw-managed-bootstrap)" = '0:0:755' || managed_runtime_assertion_failed managed-bootstrap-metadata-0:0:755 /usr/local/bin/nemoclaw-managed-bootstrap; } \
&& { test -f /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh || managed_runtime_assertion_failed managed-bootstrap-trampoline-regular-file /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh; } \
&& { test ! -L /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh || managed_runtime_assertion_failed managed-bootstrap-trampoline-non-symlink /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh; } \
&& { test "$(stat -c '%u:%g:%a' /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh)" = '0:0:444' || managed_runtime_assertion_failed managed-bootstrap-trampoline-metadata-0:0:444 /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh; } \
&& { install -d -o root -g root -m 0755 /run/nemoclaw || managed_runtime_assertion_failed runtime-directory-create /run/nemoclaw; } \
&& { test -d /run/nemoclaw || managed_runtime_assertion_failed runtime-directory /run/nemoclaw; } \
&& { test ! -L /run/nemoclaw || managed_runtime_assertion_failed runtime-directory-non-symlink /run/nemoclaw; } \
&& { test "$(stat -c '%u:%g:%a' /run/nemoclaw 2>/dev/null)" = '0:0:755' || managed_runtime_assertion_failed runtime-directory-metadata-0:0:755 /run/nemoclaw; }

# Ensure sandbox user can read blueprint files copied as root
RUN chmod -R a+rX /opt/nemoclaw-blueprint/
Expand Down
5 changes: 4 additions & 1 deletion agents/langchain-deepagents-code/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ RUN managed_runtime_assertion_failed() { \
&& { chown root:root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed owner-root-root /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \
&& { chmod 0444 /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null || managed_runtime_assertion_failed mode-0444 /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \
&& { test "$(stat -c '%u:%g:%a' /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs 2>/dev/null)" = '0:0:444' || managed_runtime_assertion_failed metadata-0:0:444 /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs; } \
&& install -d -o root -g root -m 0755 /run/nemoclaw
&& { install -d -o root -g root -m 0755 /run/nemoclaw || managed_runtime_assertion_failed runtime-directory-create /run/nemoclaw; } \
&& { test -d /run/nemoclaw || managed_runtime_assertion_failed runtime-directory /run/nemoclaw; } \
&& { test ! -L /run/nemoclaw || managed_runtime_assertion_failed runtime-directory-non-symlink /run/nemoclaw; } \
&& { test "$(stat -c '%u:%g:%a' /run/nemoclaw 2>/dev/null)" = '0:0:755' || managed_runtime_assertion_failed runtime-directory-metadata-0:0:755 /run/nemoclaw; }

COPY scripts/lib/reviewed-npm-archive.mts /scripts/lib/reviewed-npm-archive.mts
COPY scripts/patch-bundled-npm-brace-expansion.mts /scripts/patch-bundled-npm-brace-expansion.mts
Expand Down
10 changes: 10 additions & 0 deletions ci/source-shape-test-budget.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,11 +286,21 @@
"test": "keeps fork-safe labeling inside the trusted metadata boundary",
"category": "security"
},
{
"file": "test/managed-image-publication-workflow.test.ts",
"test": "builds and exercises every shipped agent from an exact PR image before merge (#7744)",
"category": "security"
},
{
"file": "test/messaging-image-env-contract.test.ts",
"test": "%s keeps the full plan in build processes but not final runtime environments (#5896)",
"category": "security"
},
{
"file": "test/mcp-tool-discovery-image-contract.test.ts",
"test": "builds managed images when reviewed runtime bundle files are group-writable (#8665)",
"category": "security"
},
{
"file": "test/mcp-tool-discovery-image-contract.test.ts",
"test": "pins reviewed packages and audits their lock outside image builds (#8253)",
Expand Down
4 changes: 2 additions & 2 deletions test/hermes-final-image-layout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@

function indexOfRequired(haystack: string, needle: string): number {
const index = haystack.indexOf(needle);
expect(index).toBeGreaterThanOrEqual(0);

Check failure on line 165 in test/hermes-final-image-layout.test.ts

View workflow job for this annotation

GitHub Actions / cli-test-shards (8)

[integration] test/hermes-final-image-layout.test.ts > Hermes final image layout > uses grouped legacy-compatible payload layers at their cache boundaries (#7611)

AssertionError: expected -1 to be greater than or equal to 0 ❯ indexOfRequired test/hermes-final-image-layout.test.ts:165:17 ❯ test/hermes-final-image-layout.test.ts:394:37
return index;
}

Expand Down Expand Up @@ -393,7 +393,7 @@
);
const managedRuntimeDirectory = indexOfRequired(
finalStage,
"&& install -d -o root -g root -m 0755 /run/nemoclaw",
"install -d -o root -g root -m 0755 /run/nemoclaw \\\n || managed_runtime_assertion_failed runtime-directory-create /run/nemoclaw; \\\n test -d /run/nemoclaw \\\n || managed_runtime_assertion_failed runtime-directory /run/nemoclaw; \\\n test ! -L /run/nemoclaw \\\n || managed_runtime_assertion_failed runtime-directory-non-symlink /run/nemoclaw; \\\n test \"$(stat -c '%u:%g:%a' /run/nemoclaw 2>/dev/null)\" = '0:0:755' \\\n || managed_runtime_assertion_failed runtime-directory-metadata-0:0:755 /run/nemoclaw",
);
const runtimeModeReplay = indexOfRequired(
finalStage,
Expand Down Expand Up @@ -425,7 +425,7 @@
expect(managedRuntimeDirectory).toBeLessThan(runtimeModeReplay);
expect(finalStage).toContain("/usr/local/bin/nemoclaw-managed-bootstrap");
expect(dockerfile).toContain(
"COPY tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/managed-startup-image-runtime.bundle /out/managed-startup-image-runtime.cjs",
"COPY --chown=0:0 --chmod=0444 tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/managed-startup-image-runtime.bundle /out/managed-startup-image-runtime.cjs",
);
expect(dockerfile).not.toContain(
"COPY src/lib/onboard/managed-bootstrap/ ./src/lib/onboard/managed-bootstrap/",
Expand Down
5 changes: 3 additions & 2 deletions test/langchain-deepagents-code-image.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@
"# explicitly before installing the root-owned managed-startup handoff.",
"USER root",
].join("\n");
const managedRuntimeDirectory = "&& install -d -o root -g root -m 0755 /run/nemoclaw";
const managedRuntimeDirectory =
"install -d -o root -g root -m 0755 /run/nemoclaw \\\n || managed_runtime_assertion_failed runtime-directory-create /run/nemoclaw; \\\n test -d /run/nemoclaw \\\n || managed_runtime_assertion_failed runtime-directory /run/nemoclaw; \\\n test ! -L /run/nemoclaw \\\n || managed_runtime_assertion_failed runtime-directory-non-symlink /run/nemoclaw; \\\n test \"$(stat -c '%u:%g:%a' /run/nemoclaw 2>/dev/null)\" = '0:0:755' \\\n || managed_runtime_assertion_failed runtime-directory-metadata-0:0:755 /run/nemoclaw";
const runtimeModeReplay = "&& chmod 444 /opt/nemoclaw-deepagents-code/generate-config.ts";

expect(dockerfile).toContain("ARG BASE_IMAGE\n");
Expand All @@ -188,7 +189,7 @@
expect(dockerfile.indexOf("cp -r /opt/nemoclaw-blueprint/*")).toBeLessThan(
dockerfile.indexOf("chown -R root:root /sandbox/.nemoclaw/blueprints"),
);
expect(dockerfile.split(managedRuntimeDirectory)).toHaveLength(2);

Check failure on line 192 in test/langchain-deepagents-code-image.test.ts

View workflow job for this annotation

GitHub Actions / cli-test-shards (2)

[integration] test/langchain-deepagents-code-image.test.ts > LangChain Deep Agents Code image contracts > hardens copied NemoClaw blueprints against sandbox-user mutation

AssertionError: expected [ Array(1) ] to have a length of 2 but got 1 - Expected + Received - 2 + 1 ❯ test/langchain-deepagents-code-image.test.ts:192:55
expect(dockerfile.indexOf("COPY --from=mcp-tool-discovery-runtime")).toBeLessThan(
dockerfile.indexOf(managedRuntimeDirectory),
);
Expand All @@ -201,7 +202,7 @@
dockerfile.indexOf(runtimeModeReplay),
);
expect(dockerfile).toContain(
"COPY tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/managed-startup-image-runtime.bundle /out/managed-startup-image-runtime.cjs",
"COPY --chown=0:0 --chmod=0444 tools/mcp-tool-discovery-runtime/reviewed-runtime-bundle/managed-startup-image-runtime.bundle /out/managed-startup-image-runtime.cjs",
);
expect(dockerfile).not.toContain(
"COPY src/lib/onboard/managed-bootstrap/ ./src/lib/onboard/managed-bootstrap/",
Expand Down
24 changes: 22 additions & 2 deletions test/managed-image-publication-workflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,11 @@ describe("complete managed-image publication workflow", () => {
}
});

// source-shape-contract: security -- PR image builds must reject a symlinked runtime path before final image contract validation
it("builds and exercises every shipped agent from an exact PR image before merge (#7744)", () => {
const workflow = readWorkflow("managed-images.yaml");
const workflow = YAML.parse(
fs.readFileSync(path.join(repoRoot, ".github/workflows/managed-images.yaml"), "utf8"),
) as Workflow;
const prBuilder = managedPrBuilder(workflow);
const matrix = prBuilder.strategy?.matrix?.include ?? [];
const steps = prBuilder.steps ?? [];
Expand Down Expand Up @@ -466,11 +469,28 @@ describe("complete managed-image publication workflow", () => {
expect(resolveBase).toContain('reference="${BASE_REPOSITORY}@${digest}"');
expect(resolveBase).toContain('actual="sha256:$(sha256sum "$exact_raw"');

expect(step(prBuilder, "Build PR managed image locally").with).toMatchObject({
const build = step(prBuilder, "Build PR managed image locally");
expect(build.with).toMatchObject({
platforms: "linux/amd64",
load: true,
push: false,
});
const runtimeDirectoryProbe = step(
prBuilder,
"Reject a symlinked runtime directory during image assembly",
);
expect(runtimeDirectoryProbe.if).toBe("${{ matrix.agent == 'langchain-deepagents-code' }}");
expect(runtimeDirectoryProbe.run).toContain("docker buildx build");
expect(runtimeDirectoryProbe.run).toContain(
"managed_runtime_assertion_failed runtime-directory-metadata-0:0:755",
);
expect(runtimeDirectoryProbe.run).toContain(
"ERROR: managed image assertion failed: runtime-directory-non-symlink path=/run/nemoclaw",
);
expect(steps.indexOf(build)).toBeLessThan(steps.indexOf(runtimeDirectoryProbe));
expect(steps.indexOf(runtimeDirectoryProbe)).toBeLessThan(
steps.indexOf(step(prBuilder, "Validate exact PR managed image contract")),
);
expect(step(prBuilder, "Exercise managed startup root stdin and hold").run).toContain(
"run-managed-image-direct-e2e.ts",
);
Expand Down
Loading
Loading