Skip to content

Commit 1de7046

Browse files
authored
Merge branch 'main' into fix/10085-config-get-doc-example
2 parents 59e05f0 + 309ee5d commit 1de7046

547 files changed

Lines changed: 5482 additions & 2467 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/e2e.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ jobs:
313313
case "${JOBS}:${TARGETS}" in
314314
:)
315315
matrix='[{"id":"ubuntu-policy-custom-missing-presets-negative","runner":"ubuntu-latest"},{"id":"ubuntu-repo-cloud-langchain-deepagents-code","runner":"ubuntu-latest"},{"id":"ubuntu-repo-cloud-openclaw","runner":"ubuntu-latest"},{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest"}]'
316-
test_matrix='[{"id":"onboard-managed-image-buildless-e2e","file":"test/onboard-managed-image-buildless-e2e.test.ts","project":"integration"},{"id":"vllm-docker-storage","file":"test/vllm-docker-storage.test.ts","project":"integration"}]'
316+
test_matrix='[{"id":"onboard-managed-image-buildless-e2e","file":"test/onboarding/onboard-managed-image-buildless-e2e.test.ts","project":"integration"},{"id":"vllm-docker-storage","file":"test/vllm-docker-storage.test.ts","project":"integration"}]'
317317
;;
318318
inference-routing: | managed-image-protected-runtime: | native-runtime-qualification-producer: | :jetson-nvmap-gpu)
319319
matrix='[]'

.github/workflows/issue-9880-staging-reproduction.yaml

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,31 @@ jobs:
1717
reproduce:
1818
if: ${{ github.repository == 'NVIDIA/NemoClaw' && github.ref == 'refs/heads/main' && github.event_name == 'workflow_dispatch' }}
1919
runs-on: ubuntu-latest
20-
timeout-minutes: 95
20+
timeout-minutes: 210
2121
env:
2222
INSTANCE_NAME: issue-9880-${{ github.run_id }}-${{ github.run_attempt }}
2323
steps:
2424
- name: Check out trusted reproduction lane
25+
timeout-minutes: 10
2526
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
2627
with:
2728
ref: ${{ github.workflow_sha }}
2829
persist-credentials: false
2930
sparse-checkout: |
30-
tools/e2e/brev-launchable-issue-9880.sh
31+
test/e2e/
32+
test/helpers/
33+
tools/e2e/
34+
package.json
35+
package-lock.json
36+
vitest.config.ts
37+
nemoclaw/vitest.project.ts
38+
tsconfig.json
39+
oxlint.config.ts
40+
oxfmt.config.ts
3141
sparse-checkout-cone-mode: false
3242

3343
- name: Authorize maintainer dispatch
44+
timeout-minutes: 5
3445
env:
3546
ACTOR: ${{ github.actor }}
3647
GITHUB_TOKEN: ${{ github.token }}
@@ -43,8 +54,20 @@ jobs:
4354
case "$role" in maintain|admin) ;; *) echo "::error::maintain or admin permission is required"; exit 1 ;; esac
4455
done
4556
57+
- name: Set up Node
58+
timeout-minutes: 10
59+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
60+
with:
61+
node-version: "22"
62+
cache: npm
63+
64+
- name: Install dependencies
65+
timeout-minutes: 10
66+
run: npm ci --ignore-scripts --no-audit --no-fund
67+
4668
- id: prepare
4769
name: Prepare Brev CLI and evidence directory
70+
timeout-minutes: 20
4871
env:
4972
BREV_API_KEY: ${{ secrets.BREV_API_KEY }}
5073
BREV_CLI_SHA256: d4aa49db1716f10308a6587778a676a0c0076bd48a212d86a421ab9550bc8f32
@@ -65,26 +88,30 @@ jobs:
6588
printf 'work_dir=%s\n' "$work_dir" >>"$GITHUB_OUTPUT"
6689
6790
- name: Reproduce issue 9880 on the staging Launchable
68-
timeout-minutes: 65
91+
timeout-minutes: 120
6992
env:
7093
BREV_LAUNCHABLE_ID: ${{ vars.NEMOCLAW_STAGING_LAUNCHABLE_ID }}
71-
GH_TOKEN: ${{ secrets.NEMOCLAW_IMAGE_DISPATCH_TOKEN }}
94+
BREV_WORKSPACE_OWNERSHIP_FILE: ${{ steps.prepare.outputs.work_dir }}/workspace-owner.json
95+
E2E_ARTIFACT_DIR: ${{ steps.prepare.outputs.work_dir }}
96+
E2E_TARGET_ID: issue-9880-staging-launchable
7297
HOME: ${{ runner.temp }}/issue-9880-home
98+
NEMOCLAW_IMAGE_DISPATCH_TOKEN: ${{ secrets.NEMOCLAW_IMAGE_DISPATCH_TOKEN }}
99+
NEMOCLAW_RUN_LIVE_E2E: "1"
73100
NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }}
74-
WORK_DIR: ${{ steps.prepare.outputs.work_dir }}
75-
run: tools/e2e/brev-launchable-issue-9880.sh
101+
run: ./node_modules/.bin/vitest run --project e2e-live test/e2e/live/issue-9880-staging-launchable.test.ts --silent=false --reporter=default
76102

77103
- name: Verify workflow-owned workspace cleanup
78104
if: ${{ always() && steps.prepare.outputs.work_dir != '' }}
79105
timeout-minutes: 15
80106
env:
81-
BREV_DELETE_TIMEOUT_SECONDS: "720"
107+
BREV_WORKSPACE_OWNERSHIP_FILE: ${{ steps.prepare.outputs.work_dir }}/workspace-owner.json
108+
E2E_ARTIFACT_DIR: ${{ steps.prepare.outputs.work_dir }}
82109
HOME: ${{ runner.temp }}/issue-9880-home
83-
WORK_DIR: ${{ steps.prepare.outputs.work_dir }}
84-
run: tools/e2e/brev-launchable-issue-9880.sh cleanup-owned-workspace
110+
run: node --experimental-strip-types tools/e2e/cleanup-brev-workspace.mts
85111

86112
- name: Remove Brev credentials
87113
if: always()
114+
timeout-minutes: 5
88115
env:
89116
HOME: ${{ runner.temp }}/issue-9880-home
90117
run: |
@@ -93,12 +120,9 @@ jobs:
93120
test ! -e "$HOME"
94121
95122
- name: Upload issue 9880 evidence
123+
timeout-minutes: 10
96124
if: ${{ always() && steps.prepare.outputs.work_dir != '' }}
97125
uses: NVIDIA/NemoClaw/.github/actions/upload-e2e-artifacts@7768e15eb90d3ee2d33432f481dfe8747e4f6d57
98126
with:
99127
name: issue-9880-staging-reproduction-${{ github.run_id }}-${{ github.run_attempt }}
100-
path: |
101-
${{ steps.prepare.outputs.work_dir }}/lane.log
102-
${{ steps.prepare.outputs.work_dir }}/issue-9880.json
103-
${{ steps.prepare.outputs.work_dir }}/issue-9880.log
104-
${{ steps.prepare.outputs.work_dir }}/cleanup.json
128+
path: ${{ steps.prepare.outputs.work_dir }}/

.github/workflows/llama-cpp-image.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ on:
1212
- "managed-inference/recipes/llama-cpp.nemotron-3-nano-30b-a3b.spark-single.v1.yaml"
1313
- "scripts/checks/export-llama-cpp-image-config.mts"
1414
- "scripts/checks/verify-llama-cpp-image-publication-evidence.sh"
15-
- "test/llama-cpp-image.test.ts"
16-
- "test/llama-cpp-image-publication-evidence.test.ts"
17-
- "test/llama-cpp-image-workflow.test.ts"
15+
- "test/inference/llama/llama-cpp-image.test.ts"
16+
- "test/inference/llama/llama-cpp-image-publication-evidence.test.ts"
17+
- "test/inference/llama/llama-cpp-image-workflow.test.ts"
1818
workflow_dispatch:
1919
inputs:
2020
publish:

.github/workflows/main.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,17 @@ jobs:
123123
- name: Audit the real patched OpenClaw distribution
124124
env:
125125
NEMOCLAW_REAL_OPENCLAW_DIST_HARNESS: "1"
126-
run: npx vitest run --project integration test/openclaw-real-patched-dist-harness.test.ts --silent=false --reporter=default
126+
run: npx vitest run --project integration test/agents/openclaw/openclaw-real-patched-dist-harness.test.ts --silent=false --reporter=default
127127

128128
- name: Verify reviewed Jaeger header handling
129129
env:
130130
NEMOCLAW_REAL_OPENCLAW_JAEGER_HARNESS: "1"
131-
run: npx vitest run --project integration test/openclaw-diagnostics-jaeger-runtime.test.ts --silent=false --reporter=default
131+
run: npx vitest run --project integration test/agents/openclaw/openclaw-diagnostics-jaeger-runtime.test.ts --silent=false --reporter=default
132132

133133
- name: Audit managed OpenClaw security finding suppressions
134134
env:
135135
NEMOCLAW_REAL_OPENCLAW_AUDIT_HARNESS: "1"
136-
run: npx vitest run --project integration test/openclaw-security-audit-suppressions-real.test.ts --silent=false --reporter=default
136+
run: npx vitest run --project integration test/agents/openclaw/openclaw-security-audit-suppressions-real.test.ts --silent=false --reporter=default
137137

138138
cli-test-shards:
139139
runs-on: ubuntu-24.04

.github/workflows/platform-vitest-main.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,10 @@ jobs:
365365
scripts/lib/normalize_mutable_config_perms.py \
366366
/usr/local/lib/nemoclaw/normalize_mutable_config_perms.py
367367
npx vitest run --project integration \
368-
test/hermes-restart-config-seal-recovery.test.ts \
368+
test/agents/hermes/hermes-restart-config-seal-recovery.test.ts \
369369
-t 'keeps the locked Hermes entry sticky-protected|lets a sandbox-group peer create state'
370370
npx vitest run --project integration \
371-
test/nemoclaw-start-perms.test.ts \
371+
test/agents/openclaw/runtime/nemoclaw-start-perms.test.ts \
372372
-t 'requires both fixed files to match|reclaims a root-owned collapsed config|leaves a root-owned recovery baseline untouched'
373373
"@
374374
Invoke-WslScript -Distro $env:WSL_DISTRO -User root -Script $script

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2163,7 +2163,7 @@ RUN set -eu; \
21632163
# dropped. The `id -nG` checks make this idempotent. Remove this block after
21642164
# the minimum supported OpenClaw sandbox base tag is v0.0.71 or newer and
21652165
# Dockerfile.base guarantees both memberships; keep that base contract covered
2166-
# by test/sandbox-provisioning.test.ts.
2166+
# by test/runtime/sandbox/sandbox-provisioning.test.ts.
21672167
# hadolint ignore=DL4006
21682168
RUN if id gateway >/dev/null 2>&1 && id sandbox >/dev/null 2>&1; then \
21692169
if ! id -nG gateway | tr ' ' '\n' | grep -qx sandbox; then \
@@ -2203,7 +2203,7 @@ RUN set -eu; \
22032203
# /etc/bash.bashrc hook, or the root-owned helper mode. Remove this block after
22042204
# the minimum supported OpenClaw sandbox base tag is v0.0.69 or newer and those
22052205
# three artifacts are guaranteed by the base image and covered by
2206-
# test/sandbox-provisioning.test.ts.
2206+
# test/runtime/sandbox/sandbox-provisioning.test.ts.
22072207
# Ref: https://github.com/NVIDIA/NemoClaw/issues/2704
22082208
# hadolint ignore=SC2028,DL4006
22092209
RUN chmod 444 /usr/local/lib/nemoclaw/sandbox-rlimits.sh \

SECURITY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ This control covers cooperating NemoClaw processes, crashes, retries, and recycl
100100
- **Runtime bind changes.** The probe runs at startup only. A backend that binds loopback at proxy-start time and later rebinds to a public interface is out of scope. Adding a periodic re-probe is a follow-up.
101101
- **Inference providers this proxy does not front.** The probe covers only what the proxy forwards to: the local Ollama daemon, or a compatible endpoint onboarded without authentication. NIM, the NemoClaw-managed Local vLLM and llama.cpp providers, remote providers, and compatible endpoints onboarded with a credential do not route through this proxy and are not covered. A vLLM server you run yourself and onboard as an unauthenticated compatible endpoint is covered, because that path is the one `noAuthProxy()` fronts.
102102

103-
**Enforced by:** `test/ollama-auth-proxy-bind-probe.test.ts` covers the `/proc` and `lsof` loopback classifiers (accepts full 127.0.0.0/8 including IPv4-mapped IPv6, refuses wildcard and LAN-scope, refuses the lsof `*` token) and pins `EXIT_BACKEND_NOT_LOOPBACK = 2`; the host CLI acts on the structured status reason, which the following tests cover. `src/lib/inference/ollama/proxy-status.test.ts` covers Ollama, compatible-endpoint, and unknown-backend remediation. `test/ollama-proxy-startup.test.ts` covers the real startup path (port conflict, spawn failure, slow bind, IPv6-only listener, reclaim of a prior NemoClaw proxy) and proves `noAuthProxy()` keeps the refusal and the endpoint remediation for a compatible endpoint, including one on the Ollama port. `test/ollama-proxy-recovery.test.ts` covers descriptor persistence, legacy migration, cross-gateway adoption, and structured recovery refusals for managed Ollama and a compatible endpoint on the same port.
103+
**Enforced by:** `test/inference/ollama/ollama-auth-proxy-bind-probe.test.ts` covers the `/proc` and `lsof` loopback classifiers (accepts full 127.0.0.0/8 including IPv4-mapped IPv6, refuses wildcard and LAN-scope, refuses the lsof `*` token) and pins `EXIT_BACKEND_NOT_LOOPBACK = 2`; the host CLI acts on the structured status reason, which the following tests cover. `src/lib/inference/ollama/proxy-status.test.ts` covers Ollama, compatible-endpoint, and unknown-backend remediation. `test/inference/ollama/ollama-proxy-startup.test.ts` covers the real startup path (port conflict, spawn failure, slow bind, IPv6-only listener, reclaim of a prior NemoClaw proxy) and proves `noAuthProxy()` keeps the refusal and the endpoint remediation for a compatible endpoint, including one on the Ollama port. `test/inference/ollama/ollama-proxy-recovery.test.ts` covers descriptor persistence, legacy migration, cross-gateway adoption, and structured recovery refusals for managed Ollama and a compatible endpoint on the same port.
104104

105105
## Documented Risk Acceptances
106106

@@ -112,6 +112,6 @@ The following security-relevant defaults are intentional. Each item names the co
112112
- **Constraint:** `/tmp/nemoclaw-proxy-env.sh` is sandbox-user-owned convenience state, not an integrity boundary. It is created with mode `0444` so independent login and exec shells can source the same credential-free settings. The Deep Agents Code runtime deliberately runs as the non-root sandbox user, unlike the root-supervised OpenClaw and Hermes startup paths.
113113
- **Compensating controls:**
114114
1. The file is credential-free by construction. `prepare_runtime_env` writes normalized proxy config and inherited trust-store paths. It does not persist LangSmith tracing, project, or API key variables.
115-
2. A regression test in [`test/langchain-deepagents-code-image.test.ts`](test/langchain-deepagents-code-image.test.ts) injects token-shaped values through LangSmith tracing and both project variables, scans the emitted env file against canonical token shapes, and fails CI if any secret-shaped value is present.
115+
2. A regression test in [`test/agents/deepagents/langchain-deepagents-code-image.test.ts`](test/agents/deepagents/langchain-deepagents-code-image.test.ts) injects token-shaped values through LangSmith tracing and both project variables, scans the emitted env file against canonical token shapes, and fails CI if any secret-shaped value is present.
116116
3. The root-owned, image-baked proxy host/port files and direct `dcode-launcher.sh` boundary remain the routing source of truth. Focused and live login-shell checks compare the sourced convenience values with that root-owned source; file metadata checks detect accidental drift but do not claim sandbox-owner tamper resistance.
117117
- **When to revisit:** If a future change adds credential-shaped values to the env-file writer, or if the Deep Agents Code runtime moves back to the root-supervised startup model, revisit the mode and the compensating controls together.

agents/hermes/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ RUN chmod -R a+rX /opt/nemoclaw-blueprint/
491491
# only repairs stale bases predating the v0.0.69 base layer, which may lack the
492492
# profile hook, bashrc hook, or root-owned helper mode. Remove it once the
493493
# minimum supported Hermes sandbox base tag guarantees those artifacts and
494-
# test/sandbox-rlimit-hooks.test.ts covers that base.
494+
# test/runtime/sandbox/sandbox-rlimit-hooks.test.ts covers that base.
495495
RUN chmod 755 /usr/local/bin/nemoclaw-start /usr/local/bin/nemoclaw-managed-startup-hold /usr/local/bin/nemoclaw-managed-bootstrap /usr/local/lib/nemoclaw/sandbox-init.sh /usr/local/lib/nemoclaw/validate-hermes-env-secret-boundary.py /usr/local/lib/nemoclaw/patch-hermes-session-list-preview.py /usr/local/lib/nemoclaw/patch-hermes-sqlite-temp-store.py /usr/local/lib/nemoclaw/patch-hermes-discord-recovery-permissions.py /usr/local/lib/nemoclaw/patch-hermes-profile-policy-defaults.py /usr/local/lib/nemoclaw/seed-hermes-dashboard-config.py /usr/local/lib/nemoclaw/hermes-runtime-config-guard.py /usr/local/lib/nemoclaw/finalize-tirith-marker.py /usr/local/lib/nemoclaw/hermes-mcp-config-transaction.py \
496496
&& chown root:root /usr/local/bin/nemoclaw-gateway-control /usr/local/lib/nemoclaw/gateway-supervisor.sh /usr/local/lib/nemoclaw/state-dir-guard.py /usr/local/lib/nemoclaw/runtime-state-mutation-control.py /usr/local/lib/nemoclaw/runtime-state-mutation-startup-gate.py /usr/local/lib/nemoclaw/runtime_state_mutation_hermes_publisher.py /usr/local/share/nemoclaw/state-lock-plan.json /usr/local/share/nemoclaw/runtime-state-mutation-publisher-v1.json /usr/local/lib/nemoclaw/managed-gateway-control.py /usr/local/lib/nemoclaw/build-hermes-mcp-digest.py /usr/local/lib/nemoclaw/hermes-cron-restore-control.py /usr/local/lib/nemoclaw/openshell-child-visible-credentials.v0.0.106.json \
497497
&& chmod 700 /usr/local/bin/nemoclaw-gateway-control /usr/local/lib/nemoclaw/hermes-cron-restore-control.py \

agents/hermes/hermes-wrapper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
# either Hermes CLI native env-var reference support (an upstream
4141
# change) or a redesigned dashboard/runtime contract that no longer
4242
# needs an `sk-`-prefixed rewrite sentinel in the rendered config.
43-
# - Regression test: `test/hermes-gateway-wrapper.test.ts` —
43+
# - Regression test: `test/agents/hermes/hermes-gateway-wrapper.test.ts` —
4444
# `masks every api_key emitted by the managed policy ...` derives a
4545
# fixture from `buildHermesManagedPolicy()` and asserts no raw sentinel
4646
# survives in stdout for `config show`.

agents/hermes/patch-profile-policy-defaults.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
the managed-policy values to a config-less named profile across
3535
``DEFAULT_CONFIG`` and every independent fallback listed above. The unmodified
3636
upstream files must then pass the ``profile-policy`` image probe and
37-
``test/hermes-profile-policy-defaults.test.ts``.
37+
``test/agents/hermes/hermes-profile-policy-defaults.test.ts``.
3838
"""
3939

4040
from __future__ import annotations

0 commit comments

Comments
 (0)