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
1 change: 0 additions & 1 deletion .github/workflows/base-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ on:
- "scripts/security/build-perl-security-packages.sh"
- "scripts/security/patches/libssh2-1.11.1-cve-2026.patch"
- "scripts/security/patches/python3.13-htmlparser-cve-2026-15308.patch"
- "scripts/checks/node-tar-image-scan.mts"
- "scripts/patch-bundled-npm-brace-expansion.mts"
- "scripts/lib/patch-bundled-npm-ip-address.mts"
- "scripts/patch-bundled-npm-tar.mts"
Expand Down
18 changes: 0 additions & 18 deletions .github/workflows/managed-images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -751,26 +751,8 @@ jobs:
test "$(stat -c '%u:%g:%a' /usr/local/lib/nemoclaw/managed-startup-image-runtime.cjs)" = "0:0:444"
test -x "$REQUIRED_BINARY"
test -r /opt/nemoclaw-blueprint/blueprint.yaml
test -r /usr/local/share/nemoclaw/node-tar-inventory.json
test ! -e /usr/local/share/nemoclaw/corporate-ca.pem
test ! -L /usr/local/share/nemoclaw/corporate-ca.pem
node <<'VALIDATE_NODE_TAR'
const fs = require("node:fs");
const scan = JSON.parse(
fs.readFileSync("/usr/local/share/nemoclaw/node-tar-inventory.json", "utf8"),
);
if (
scan.schema !== 1 ||
!Number.isInteger(scan.packageCount) ||
scan.packageCount < 1 ||
!Array.isArray(scan.packages) ||
scan.packages.length !== scan.packageCount ||
scan.packages.some((entry) => entry.status !== "fixed")
) {
throw new Error("completed node-tar scan is missing or unsafe");
}
VALIDATE_NODE_TAR

test "$NEMOCLAW_MANAGED_IMAGE_CAPABILITY_UNION" = "1"
case "$AGENT" in
openclaw)
Expand Down
93 changes: 0 additions & 93 deletions .github/workflows/sandbox-images-and-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,37 +94,6 @@ jobs:
scripts/check-production-build-args.sh "${build_args[@]}"
docker build "${build_args[@]}" -t nemoclaw-production .

- name: Scan completed OpenClaw image for node-tar
id: node-tar-scan
shell: bash
run: |
set -euo pipefail
image_id="$(docker image inspect --format '{{.Id}}' nemoclaw-production)"
docker run --rm \
--network none \
--read-only \
--cap-drop ALL \
--cap-add DAC_READ_SEARCH \
--security-opt no-new-privileges \
--pids-limit 64 \
--memory 256m \
--entrypoint node \
-v "${{ github.workspace }}/scripts/checks/node-tar-image-scan.mts:/scripts/checks/node-tar-image-scan.mts:ro" \
nemoclaw-production \
--experimental-strip-types /scripts/checks/node-tar-image-scan.mts \
--root / \
--image "${image_id}" \
| tee /tmp/openclaw-node-tar-inventory.json

- name: Upload OpenClaw node-tar inventory
if: ${{ always() && steps.node-tar-scan.outcome != 'skipped' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: openclaw-node-tar-inventory
path: /tmp/openclaw-node-tar-inventory.json
if-no-files-found: error
retention-days: 14

- name: Build sandbox test image (fixtures layered on production)
run: docker build -f test/Dockerfile.sandbox --build-arg BASE_IMAGE=nemoclaw-production -t nemoclaw-sandbox-test .

Expand Down Expand Up @@ -242,37 +211,6 @@ jobs:
/opt/hermes/.venv/bin/python -I -c "import ssl; assert ssl.create_default_context().get_ca_certs()"
'

- name: Scan completed Hermes image for node-tar
id: node-tar-scan
shell: bash
run: |
set -euo pipefail
image_id="$(docker image inspect --format '{{.Id}}' nemoclaw-hermes-production)"
docker run --rm \
--network none \
--read-only \
--cap-drop ALL \
--cap-add DAC_READ_SEARCH \
--security-opt no-new-privileges \
--pids-limit 64 \
--memory 256m \
--entrypoint node \
-v "${{ github.workspace }}/scripts/checks/node-tar-image-scan.mts:/scripts/checks/node-tar-image-scan.mts:ro" \
nemoclaw-hermes-production \
--experimental-strip-types /scripts/checks/node-tar-image-scan.mts \
--root / \
--image "${image_id}" \
| tee /tmp/hermes-node-tar-inventory.json

- name: Upload Hermes node-tar inventory
if: ${{ always() && steps.node-tar-scan.outcome != 'skipped' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: hermes-node-tar-inventory
path: /tmp/hermes-node-tar-inventory.json
if-no-files-found: error
retention-days: 14

- name: Verify sandbox user can read copied files
run: |
set -euo pipefail
Expand Down Expand Up @@ -548,37 +486,6 @@ jobs:
scripts/check-production-build-args.sh "${build_args[@]}"
docker build "${build_args[@]}" -t nemoclaw-production-arm64 .

- name: Scan completed OpenClaw arm64 image for node-tar
id: node-tar-scan
shell: bash
run: |
set -euo pipefail
image_id="$(docker image inspect --format '{{.Id}}' nemoclaw-production-arm64)"
docker run --rm \
--network none \
--read-only \
--cap-drop ALL \
--cap-add DAC_READ_SEARCH \
--security-opt no-new-privileges \
--pids-limit 64 \
--memory 256m \
--entrypoint node \
-v "${{ github.workspace }}/scripts/checks/node-tar-image-scan.mts:/scripts/checks/node-tar-image-scan.mts:ro" \
nemoclaw-production-arm64 \
--experimental-strip-types /scripts/checks/node-tar-image-scan.mts \
--root / \
--image "${image_id}" \
| tee /tmp/openclaw-arm64-node-tar-inventory.json

- name: Upload OpenClaw arm64 node-tar inventory
if: ${{ always() && steps.node-tar-scan.outcome != 'skipped' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: openclaw-arm64-node-tar-inventory
path: /tmp/openclaw-arm64-node-tar-inventory.json
if-no-files-found: error
retention-days: 14

- name: Build sandbox test image on arm64
run: docker build -f test/Dockerfile.sandbox --build-arg BASE_IMAGE=nemoclaw-production-arm64 -t nemoclaw-sandbox-test-arm64 .

Expand Down
11 changes: 1 addition & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -1235,10 +1235,10 @@
# CHAT_UI_URL is a non-loopback address (Brev Launchable, remote deployments)
# since terminal-based pairing is impossible in those contexts.
# Default: "0" (device auth enabled for local deployments — secure by default).
ARG NEMOCLAW_DISABLE_DEVICE_AUTH=0

Check warning on line 1238 in Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (OpenClaw)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "NEMOCLAW_DISABLE_DEVICE_AUTH") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 1238 in Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (OpenClaw)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "NEMOCLAW_DISABLE_DEVICE_AUTH") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
# Internal audit provenance for the opt-out above. Standard onboarding rewrites
# this to managed-onboard; direct image builders retain operator provenance.
ARG NEMOCLAW_DEVICE_AUTH_OPT_OUT_SOURCE=operator

Check warning on line 1241 in Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (OpenClaw)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "NEMOCLAW_DEVICE_AUTH_OPT_OUT_SOURCE") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 1241 in Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (OpenClaw)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "NEMOCLAW_DEVICE_AUTH_OPT_OUT_SOURCE") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
# Compatibility build arg for older custom Dockerfiles and rebuild tooling.
# NemoClaw-managed images intentionally do not consume it; gateway auth tokens
# are generated at container startup and are never baked into image layers.
Expand Down Expand Up @@ -1272,7 +1272,7 @@
# NEMOCLAW_MESSAGING_PLAN_B64 intentionally remains ARG-only: Docker exposes it
# to build RUN processes without retaining the full plan in the final image env.
# Direct ARG interpolation into inline source is a code injection vector (C-2).
ENV NEMOCLAW_MODEL=${NEMOCLAW_MODEL} \

Check warning on line 1275 in Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (OpenClaw)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "NEMOCLAW_DISABLE_DEVICE_AUTH") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 1275 in Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (OpenClaw)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "NEMOCLAW_DEVICE_AUTH_OPT_OUT_SOURCE") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 1275 in Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (OpenClaw)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "NEMOCLAW_DEVICE_AUTH_OPT_OUT_SOURCE") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 1275 in Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (OpenClaw)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "NEMOCLAW_DISABLE_DEVICE_AUTH") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
NEMOCLAW_INFERENCE_PROVIDER_ID=${NEMOCLAW_INFERENCE_PROVIDER_ID} \
NEMOCLAW_UPSTREAM_PROVIDER=${NEMOCLAW_UPSTREAM_PROVIDER} \
NEMOCLAW_PRIMARY_MODEL_REF=${NEMOCLAW_PRIMARY_MODEL_REF} \
Expand Down Expand Up @@ -1857,9 +1857,6 @@
fi; \
fi

# Gate the completed local filesystem too; CI repeats this scan in an isolated
# container and retains evidence keyed to the final image ID.
COPY scripts/checks/node-tar-image-scan.mts /scripts/checks/node-tar-image-scan.mts
RUN check_metadata() { \
metadata_path="$1"; \
expected_metadata="$2"; \
Expand All @@ -1882,13 +1879,7 @@
&& check_metadata /usr/local/bin/nemoclaw-gateway-control 'root:root:700' \
&& check_metadata /usr/local/lib/nemoclaw/state-dir-guard.py 'root:root:500' \
&& check_metadata /usr/local/share/nemoclaw/state-lock-plan.json 'root:root:444' \
&& check_metadata /usr/local/lib/nemoclaw/preloads/sandbox-safety-net.js 'root:root:644' \
&& check_metadata /scripts/checks/node-tar-image-scan.mts 'root:root:755' \
&& install -d -m 0755 /usr/local/share/nemoclaw \
&& node --experimental-strip-types /scripts/checks/node-tar-image-scan.mts \
--root / --image build:openclaw \
> /usr/local/share/nemoclaw/node-tar-inventory.json \
&& chmod 0444 /usr/local/share/nemoclaw/node-tar-inventory.json
&& check_metadata /usr/local/lib/nemoclaw/preloads/sandbox-safety-net.js 'root:root:644'

# Health check: poll the gateway's /health endpoint so Docker (and Compose)
# can detect and restart unhealthy containers in standalone deployments.
Expand Down
8 changes: 0 additions & 8 deletions Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -665,11 +665,3 @@ RUN { \
&& /usr/bin/setpriv --reuid=sandbox --regid=sandbox --init-groups -- env HOME=/sandbox bash -lc 'command -v brew' | grep -qx /usr/local/bin/brew \
&& /usr/bin/setpriv --reuid=sandbox --regid=sandbox --init-groups -- env HOME=/sandbox bash -lc 'brew --prefix' | grep -qx /home/linuxbrew/.linuxbrew \
&& /usr/bin/setpriv --reuid=sandbox --regid=sandbox --init-groups -- env HOME=/sandbox bash -lc "case \":\${PATH}:\" in *:/home/linuxbrew/.linuxbrew/bin:*) exit 0 ;; *) exit 1 ;; esac"

# Gate the exact completed base filesystem before it can be published.
COPY scripts/checks/node-tar-image-scan.mts /scripts/checks/node-tar-image-scan.mts
RUN install -d -m 0755 /usr/local/share/nemoclaw \
&& node --experimental-strip-types /scripts/checks/node-tar-image-scan.mts \
--root / --image build:openclaw-base \
> /usr/local/share/nemoclaw/node-tar-inventory.json \
&& chmod 0444 /usr/local/share/nemoclaw/node-tar-inventory.json
15 changes: 1 addition & 14 deletions agents/hermes/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,6 @@ COPY agents/hermes/hermes-wrapper.py /usr/local/lib/nemoclaw/hermes-wrapper.py
COPY agents/hermes/validate-cli-adapter.py /usr/local/lib/nemoclaw/validate-hermes-cli-adapter.py
COPY agents/hermes/hermes-cli-adapter-v1.json /usr/local/share/nemoclaw/hermes-cli-adapter-v1.json

FROM scratch AS hermes-scan-payload

COPY scripts/checks/node-tar-image-scan.mts /scripts/checks/node-tar-image-scan.mts

# hadolint ignore=DL3006
FROM ${BASE_IMAGE}
Expand Down Expand Up @@ -1135,9 +1132,6 @@ RUN if [ "$NEMOCLAW_DARWIN_VM_COMPAT" = "1" ]; then \
chmod a+rw /sandbox/.bashrc /sandbox/.profile; \
fi

# Gate the completed local filesystem too; CI repeats this scan in an isolated
# container and retains evidence keyed to the final image ID.
COPY --from=hermes-scan-payload / /

# These executables are git-tracked 0755 but check out group-writable (0775)
# under umask 002, and COPY carries that source mode into the image. Normalize
Expand All @@ -1146,7 +1140,6 @@ COPY --from=hermes-scan-payload / /
RUN chmod 755 \
/usr/local/lib/nemoclaw/hermes-wrapper.py \
/usr/local/lib/nemoclaw/validate-hermes-cli-adapter.py \
/scripts/checks/node-tar-image-scan.mts \
&& chmod 444 /usr/local/share/nemoclaw/hermes-cli-adapter-v1.json

RUN check_metadata() { \
Expand Down Expand Up @@ -1190,13 +1183,7 @@ RUN check_metadata() { \
&& check_metadata /usr/local/lib/nemoclaw/preloads/sandbox-safety-net.js 'root:root 444' \
&& check_metadata /usr/local/lib/nemoclaw/hermes-wrapper.py 'root:root 755' \
&& check_metadata /usr/local/lib/nemoclaw/validate-hermes-cli-adapter.py 'root:root 755' \
&& check_metadata /usr/local/share/nemoclaw/hermes-cli-adapter-v1.json 'root:root 444' \
&& check_metadata /scripts/checks/node-tar-image-scan.mts 'root:root 755' \
&& install -d -m 0755 /usr/local/share/nemoclaw \
&& node --experimental-strip-types /scripts/checks/node-tar-image-scan.mts \
--root / --image build:hermes \
> /usr/local/share/nemoclaw/node-tar-inventory.json \
&& chmod 0444 /usr/local/share/nemoclaw/node-tar-inventory.json
&& check_metadata /usr/local/share/nemoclaw/hermes-cli-adapter-v1.json 'root:root 444'

# Verify the immutable security package inventory in the completed image.
# hadolint ignore=DL4006
Expand Down
10 changes: 2 additions & 8 deletions agents/hermes/Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -564,17 +564,11 @@ RUN chmod -R a+rX /opt/hermes/.venv \
&& test -r /opt/hermes/.venv/pyvenv.cfg \
&& su -s /bin/sh sandbox -c '/opt/hermes/.venv/bin/python3 -c "import urllib.request"'

# Gate the exact completed base filesystem before it can be published.
COPY scripts/checks/node-tar-image-scan.mts /scripts/checks/node-tar-image-scan.mts
# Reject build-only paths before the base image can be published.
RUN set -eu; \
for build_only_path in /opt/hermes/tests /root/.npm /root/.cache/electron /root/.cache/node-gyp /root/.cache/uv; do \
if [ -e "$build_only_path" ] || [ -L "$build_only_path" ]; then \
echo "ERROR: build-only Hermes path leaked into the base image: $build_only_path" >&2; \
exit 1; \
fi; \
done; \
install -d -m 0755 /usr/local/share/nemoclaw \
&& node --experimental-strip-types /scripts/checks/node-tar-image-scan.mts \
--root / --image build:hermes-base \
> /usr/local/share/nemoclaw/node-tar-inventory.json \
&& chmod 0444 /usr/local/share/nemoclaw/node-tar-inventory.json
done
10 changes: 2 additions & 8 deletions agents/langchain-deepagents-code/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
strings "$binary" | grep -Fq '/usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh'

# hadolint ignore=DL3006
FROM ${BASE_IMAGE}

Check warning on line 95 in agents/langchain-deepagents-code/Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (Deep Agents Code)

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG ${BASE_IMAGE} results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

Check warning on line 95 in agents/langchain-deepagents-code/Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (Deep Agents Code)

Default value for global ARG results in an empty or invalid base image name

InvalidDefaultArgInFrom: Default value for ARG ${BASE_IMAGE} results in empty or invalid base image name More info: https://docs.docker.com/go/dockerfile/rule/invalid-default-arg-in-from/

# The supplied base may end as a non-root runtime user. Reset the build user
# explicitly before installing the root-owned managed-startup handoff.
Expand Down Expand Up @@ -294,7 +294,7 @@
&& env -i /usr/local/bin/dcode.real --version \
&& env -i /usr/local/bin/deepagents-code --version

ENV HOME=/sandbox \

Check warning on line 297 in agents/langchain-deepagents-code/Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (Deep Agents Code)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "DEEPAGENTS_CODE_OPENAI_API_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 297 in agents/langchain-deepagents-code/Dockerfile

View workflow job for this annotation

GitHub Actions / PR build and direct managed startup (Deep Agents Code)

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "DEEPAGENTS_CODE_OPENAI_API_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
VIRTUAL_ENV=/opt/venv \
PATH="/usr/local/bin:/opt/venv/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin" \
NEMOCLAW_MODEL=${NEMOCLAW_MODEL} \
Expand Down Expand Up @@ -354,19 +354,13 @@
chmod a+rw /sandbox/.bashrc /sandbox/.profile; \
fi

# Gate the completed local filesystem for dynamically built managed images.
COPY scripts/checks/node-tar-image-scan.mts /scripts/checks/node-tar-image-scan.mts
# Verify the managed bootstrap files in dynamically built images.
RUN 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)" = 'root:root: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)" = 'root:root:444' \
&& install -d -m 0755 /usr/local/share/nemoclaw \
&& node --experimental-strip-types /scripts/checks/node-tar-image-scan.mts \
--root / --image build:deepagents-code \
> /usr/local/share/nemoclaw/node-tar-inventory.json \
&& chmod 0444 /usr/local/share/nemoclaw/node-tar-inventory.json
&& test "$(stat -c '%U:%G:%a' /usr/local/lib/nemoclaw/managed-bootstrap-trampoline.sh)" = 'root:root:444'

# Verify the immutable security package inventory in the completed image.
# hadolint ignore=DL4006
Expand Down
8 changes: 0 additions & 8 deletions agents/langchain-deepagents-code/Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,3 @@ ENV HOME=/sandbox \
DEEPAGENTS_CODE_NO_UPDATE_CHECK=1

WORKDIR /sandbox

# Gate the exact completed base filesystem before it can be published.
COPY scripts/checks/node-tar-image-scan.mts /scripts/checks/node-tar-image-scan.mts
RUN install -d -m 0755 /usr/local/share/nemoclaw \
&& node --experimental-strip-types /scripts/checks/node-tar-image-scan.mts \
--root / --image build:deepagents-code-base \
> /usr/local/share/nemoclaw/node-tar-inventory.json \
&& chmod 0444 /usr/local/share/nemoclaw/node-tar-inventory.json
9 changes: 6 additions & 3 deletions docs/security/sandbox-base-2026-07-25-dependency-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

Date: 2026-07-25

Last updated: 2026-08-03
Last updated: August 8, 2026

## Scope

Expand Down Expand Up @@ -107,7 +107,10 @@ The replacement helper:
10. invokes npm and npx only after the fixed package is active.

All managed base images apply the helper after the complete npm upgrade.
Their final images reassert the same idempotent contract so the scanned filesystem, not an intermediate stage, owns the dependency boundary.
Each final image reruns the idempotent helper against `/usr/local/lib/node_modules/npm`.
The final image stage therefore owns the bundled npm dependency boundary.
NemoClaw image builds and image workflows do not scan the complete image filesystem for other `node_modules/tar` packages.
They do not create or retain a node-tar inventory artifact.

### Perl component versions

Expand Down Expand Up @@ -193,4 +196,4 @@ Required evidence for the final pull-request head:
- real reviewed npm archive replacement using the registry artifact;
- repository formatting and type checks;
- amd64 and arm64 builds for the OpenClaw, Hermes, and Deep Agents Code base images; and
- completed-image dependency inventory.
- final-stage npm remediation ordering checks for OpenClaw, Hermes, and Deep Agents Code.
Loading
Loading