diff --git a/test/e2e-scenario/support-tests/platform-parity-cloud-experimental.test.ts b/test/e2e-scenario/support-tests/platform-parity-cloud-experimental.test.ts index 1a963632625..d9c61f87fd4 100644 --- a/test/e2e-scenario/support-tests/platform-parity-cloud-experimental.test.ts +++ b/test/e2e-scenario/support-tests/platform-parity-cloud-experimental.test.ts @@ -87,6 +87,28 @@ describe("P0-E cloud-experimental parity guardrails", () => { expect(result.stdout.trim()).toBe("NO_NEWLINE_IN_COMMAND"); }); + it("keeps Deep Agents secret-boundary probe command single-line for OpenShell exec", () => { + const result = spawnSync( + "bash", + [ + path.join( + process.cwd(), + "test/e2e/e2e-cloud-experimental/checks/08-deepagents-code-secret-boundary.sh", + ), + ], + { + encoding: "utf8", + env: { + NEMOCLAW_E2E_SECRET_BOUNDARY_SELF_TEST: "probe-command-shape", + PATH: process.env.PATH ?? "/usr/bin:/bin", + }, + }, + ); + + expect(result.status).toBe(0); + expect(result.stdout).toContain("NO_NEWLINE_IN_COMMAND"); + }); + it("registers executable Deep Agents cloud-experimental checks", () => { expect(DEEPAGENTS_CLOUD_EXPERIMENTAL_CHECKS).toEqual([ "test/e2e/e2e-cloud-experimental/checks/05-deepagents-code-landlock-readonly.sh", diff --git a/test/e2e/e2e-cloud-experimental/checks/08-deepagents-code-secret-boundary.sh b/test/e2e/e2e-cloud-experimental/checks/08-deepagents-code-secret-boundary.sh index 16680908684..fa12be8e218 100755 --- a/test/e2e/e2e-cloud-experimental/checks/08-deepagents-code-secret-boundary.sh +++ b/test/e2e/e2e-cloud-experimental/checks/08-deepagents-code-secret-boundary.sh @@ -34,17 +34,17 @@ sandbox_exec() { openshell sandbox exec --name "$SANDBOX_NAME" -- bash -c "$1" 2>&1 } -dcode_secret_probe() { - local command="$1" - sandbox_exec " -tmp=\$(mktemp /tmp/dcode-secret-boundary.XXXXXX) -${command} >\"\$tmp\" 2>&1 -status=\$? -cat \"\$tmp\" -rm -f \"\$tmp\" -printf 'DCODE_EXIT:%s\n' \"\$status\" -exit 0 -" +dcode_secret_probe_runtime_env() { + # Keep this probe single-line: OpenShell rejects newline-bearing exec arguments. + local remote_cmd + remote_cmd="tmp=\$(mktemp /tmp/dcode-secret-boundary.XXXXXX); env OPENAI_API_KEY=${FAKE_SECRET@Q} dcode -n 'Reply with the single word PING' >\"\$tmp\" 2>&1; status=\$?; cat \"\$tmp\"; rm -f \"\$tmp\"; printf 'DCODE_EXIT:%s\\n' \"\$status\"; exit 0" + sandbox_exec "$remote_cmd" +} + +dcode_secret_probe_env_file() { + local remote_cmd + remote_cmd="tmp=\$(mktemp /tmp/dcode-secret-boundary.XXXXXX); dcode -n 'Reply with the single word PING' >\"\$tmp\" 2>&1; status=\$?; cat \"\$tmp\"; rm -f \"\$tmp\"; printf 'DCODE_EXIT:%s\\n' \"\$status\"; exit 0" + sandbox_exec "$remote_cmd" } make_log_marker() { @@ -191,6 +191,23 @@ assert_no_rejected_interval_audit_logs() { PASSED=0 FAILED=0 +if [ "${NEMOCLAW_E2E_SECRET_BOUNDARY_SELF_TEST:-}" = "probe-command-shape" ]; then + sandbox_exec() { + case "$1" in + *$'\n'*) + printf '%s\n' "NEWLINE_IN_COMMAND" + return 1 + ;; + *) + printf '%s\n' "NO_NEWLINE_IN_COMMAND" + return 0 + ;; + esac + } + dcode_secret_probe_runtime_env + exit 0 +fi + if ! sandbox_exec "test -d /sandbox/.deepagents && command -v dcode >/dev/null 2>&1" >/dev/null; then info "SKIP: sandbox '${SANDBOX_NAME}' is not a Deep Agents Code sandbox" exit 0 @@ -202,7 +219,7 @@ enable_openshell_audit_logs runtime_log_marker="$(make_log_marker runtime-env)" runtime_audit_start="$(($(date +%s) - 1))" mark_sandbox_logs "$runtime_log_marker" -runtime_output="$(dcode_secret_probe "env OPENAI_API_KEY=${FAKE_SECRET@Q} dcode -n 'Reply with the single word PING'" || true)" +runtime_output="$(dcode_secret_probe_runtime_env || true)" runtime_logs="$(sandbox_logs_since_marker "$runtime_log_marker" || true)" runtime_audit_logs="$(openshell_audit_logs_since_epoch "$runtime_audit_start" || true)" assert_secret_rejected "runtime environment injection" "$runtime_output" "OPENAI_API_KEY" @@ -220,7 +237,7 @@ env_before_hash="$(sandbox_exec "sha256sum ${DEEPAGENTS_ENV_FILE@Q} | awk '{prin env_log_marker="$(make_log_marker env-file)" env_audit_start="$(($(date +%s) - 1))" mark_sandbox_logs "$env_log_marker" -env_output="$(dcode_secret_probe "dcode -n 'Reply with the single word PING'" || true)" +env_output="$(dcode_secret_probe_env_file || true)" env_logs="$(sandbox_logs_since_marker "$env_log_marker" || true)" env_audit_logs="$(openshell_audit_logs_since_epoch "$env_audit_start" || true)" env_after_hash="$(sandbox_exec "sha256sum ${DEEPAGENTS_ENV_FILE@Q} | awk '{print \$1}'" || true)" diff --git a/test/langchain-deepagents-code-image.test.ts b/test/langchain-deepagents-code-image.test.ts index 4fd3468d3ca..50790ae0967 100644 --- a/test/langchain-deepagents-code-image.test.ts +++ b/test/langchain-deepagents-code-image.test.ts @@ -433,6 +433,13 @@ describe("LangChain Deep Agents Code image contracts", () => { expect(secretBoundaryCheck).toContain("Case: Deep Agents Code dcode secret boundary"); expect(secretBoundaryCheck).toContain("env OPENAI_API_KEY="); expect(secretBoundaryCheck).toContain("dcode -n 'Reply with the single word PING'"); + expect(secretBoundaryCheck).toContain("dcode_secret_probe_runtime_env"); + expect(secretBoundaryCheck).toContain("dcode_secret_probe_env_file"); + expect(secretBoundaryCheck).toContain("remote_cmd="); + expect(secretBoundaryCheck).toContain("OpenShell rejects newline-bearing exec"); + expect(secretBoundaryCheck).toContain("NEMOCLAW_E2E_SECRET_BOUNDARY_SELF_TEST"); + expect(secretBoundaryCheck).toContain("NO_NEWLINE_IN_COMMAND"); + expect(secretBoundaryCheck).toContain("DCODE_EXIT:%s\\\\n"); expect(secretBoundaryCheck).toContain("DCODE_EXIT:0"); expect(secretBoundaryCheck).toContain("refusing to start"); expect(secretBoundaryCheck).toContain("NETWORK_LOG_PATTERN=");