Skip to content

security: use argv for host-side helper calls - #2476

Closed
WilliamK112 wants to merge 3 commits into
NVIDIA:mainfrom
WilliamK112:security/argv-callers
Closed

security: use argv for host-side helper calls#2476
WilliamK112 wants to merge 3 commits into
NVIDIA:mainfrom
WilliamK112:security/argv-callers

Conversation

@WilliamK112

@WilliamK112 WilliamK112 commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a small Phase 1 pass on #1889.

It converts shell-string helper calls to argv-style execution where the command does not actually need a shell, while intentionally leaving explicit shell-dependent cases in place, such as:

  • pipelines
  • shell builtins / shell environment composition
  • detached background starts that currently rely on shell redirection

What changed

  • switch host-side probe commands in src/lib/preflight.ts to argv form
  • switch Docker helper calls in src/lib/onboard.ts to argv form
  • replace the gateway volume cleanup pipe with explicit list + remove steps
  • add focused regression tests covering the new argv callsites

Validation

  • npm run build:cli
  • npm test -- test/argv-callers.test.ts

Notes

I also checked the broader test suite locally, but there are existing unrelated failures/noise on current main, so I kept validation scoped to the touched paths for this PR.

Summary by CodeRabbit

  • Bug Fixes

    • Safer, more reliable system probing and cleanup across preflight, host/container diagnostics, network/gateway discovery, and volume/port cleanup — reduces flaky failures and accidental shell-parsing issues and preserves best-effort behavior.
  • Tests

    • Added tests validating argv-style command execution patterns for host assessment, Docker/network probes, DNS/container diagnostics, and gateway state checks.

@copy-pr-bot

copy-pr-bot Bot commented Apr 25, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Apr 25, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Replaces shell-string command invocations with argv-array command calls across onboarding and preflight modules, adds a CaptureCommand type and updates related interfaces, and introduces tests that assert compiled callsites use argv-array invocations.

Changes

Cohort / File(s) Summary
Onboard CLI & helpers
src/lib/onboard.ts
Replaced shell pipelines and shell-quoted command strings with argv-array invocations for Docker volume listing/removal, docker inspect/exec, ps/kill, which, and hostname -I; retains ignoreError: true and best-effort deletion semantics.
Preflight checks & types
src/lib/preflight.ts
Adds CaptureCommand type; updates AssessHostOpts.runCaptureImpl, ProbeContainerDnsOpts, and related defaults to accept argv arrays; converts probes (e.g., which, df output parsing, systemctl, grep/tee swap persistence, docker network inspect) to argv-style calls and adjusts parsing/flow.
Tests (argv callsites)
test/argv-callers.test.ts
New Vitest suite that imports compiled dist modules and asserts runCaptureImpl/capture callers are invoked with argv-array commands (checks which, docker run ... nslookup, docker network inspect and docker inspect --type container call shapes and parsing behavior).

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I nudged the shell's tangled vines away,
Each arg now lined up neat in bright array.
No pipes or quotes to trip the night,
Tests keep watch with careful light.
A carrot-coded hop—code runs alright 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'security: use argv for host-side helper calls' directly and clearly summarizes the main change: migrating host-side shell-string command calls to safer argv-style execution.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/lib/onboard.ts (1)

2598-2609: Extract gateway-volume cleanup into a shared helper.

This argv-based cleanup looks good, but the orphaned-container path later in the same file still carries a separate shell-pipeline implementation for the same volume removal. Keeping both versions around makes the security fix easy to miss the next time this logic changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/onboard.ts` around lines 2598 - 2609, Extract the duplicated Docker
volume cleanup into a shared helper (e.g., create a function
removeGatewayVolumes(gatewayName: string)) that uses
runCapture(["docker","volume","ls","-q","--filter",
`name=openshell-cluster-${gatewayName}`], {ignoreError:true}) to compute
volumeIds, then calls run(["docker","volume","rm", ...volumeIds],
{ignoreError:true, suppressOutput:true}) if any exist; replace the inline logic
that uses runCapture/run at the volume cleanup site and the separate
orphaned-container pipeline that performs the same removal to call
removeGatewayVolumes(GATEWAY_NAME) instead so both paths share one
implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/preflight.ts`:
- Around line 715-724: The current grep call in existingFstabEntry uses a plain
substring search which can match commented lines or unrelated paths; update the
check so it only matches active (non-commented) fstab entries for /swapfile by
changing the command invoked by run([...]) to use an anchored regex (e.g., grep
-qE with a pattern like '^[[:space:]]*[^#].*/swapfile\b') so only uncommented
lines containing /swapfile are detected; keep the subsequent runCapture([...
"sudo", "tee", "-a", "/etc/fstab"]) logic unchanged so the append happens only
when no active entry exists.

In `@test/argv-callers.test.ts`:
- Line 1: Add the required SPDX header lines to the top of this test file (above
the existing import { afterEach, describe, expect, it, vi } from "vitest";
line): insert the exact comment lines "// SPDX-FileCopyrightText: Copyright (c)
2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved." and "//
SPDX-License-Identifier: Apache-2.0" as the first two lines of the file.
- Around line 3-123: This test uses CommonJS require/require.cache which breaks
ESM test runner—replace require.resolve/require/require.cache usage with ESM
dynamic imports and Vitest module-reset/mocking: use string module specifiers
(e.g. const preflightPath = "../dist/lib/preflight.js") and await
import(preflightPath) to load assessHost, probeContainerDns,
getDockerBridgeGatewayIp, and onboard.getGatewayClusterContainerState, call
vi.resetModules() (or vi.restoreAllMocks() + vi.resetModules()) in afterEach
instead of deleting require.cache, and replace manual cache injection for runner
(where you override runCapture) with vi.mock(runnerPath, async () => ({
...(await vi.importActual(runnerPath)), runCapture: vi.fn(() => "running
healthy\n") })) so the tests use Vitest’s ESM-aware mocking and module
lifecycle.

---

Nitpick comments:
In `@src/lib/onboard.ts`:
- Around line 2598-2609: Extract the duplicated Docker volume cleanup into a
shared helper (e.g., create a function removeGatewayVolumes(gatewayName:
string)) that uses runCapture(["docker","volume","ls","-q","--filter",
`name=openshell-cluster-${gatewayName}`], {ignoreError:true}) to compute
volumeIds, then calls run(["docker","volume","rm", ...volumeIds],
{ignoreError:true, suppressOutput:true}) if any exist; replace the inline logic
that uses runCapture/run at the volume cleanup site and the separate
orphaned-container pipeline that performs the same removal to call
removeGatewayVolumes(GATEWAY_NAME) instead so both paths share one
implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4cd66351-0ab1-47ac-9975-34f03d2f7bbc

📥 Commits

Reviewing files that changed from the base of the PR and between 9c5a42a and 2f20e7d.

📒 Files selected for processing (3)
  • src/lib/onboard.ts
  • src/lib/preflight.ts
  • test/argv-callers.test.ts

Comment thread src/lib/preflight.ts
Comment on lines +715 to +724
const existingFstabEntry =
run(["grep", "-q", "/swapfile", "/etc/fstab"], {
ignoreError: true,
suppressOutput: true,
}).status === 0;
if (!existingFstabEntry) {
runCapture(["sudo", "tee", "-a", "/etc/fstab"], {
ignoreError: false,
input: "/swapfile none swap sw 0 0\n",
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Match only active /swapfile entries in /etc/fstab.

Line 716 uses a plain substring grep, so a commented entry or an unrelated path containing /swapfile will suppress the append. The swap file still works for the current boot, but it will not be re-enabled after reboot.

Suggested fix
     const existingFstabEntry =
-      run(["grep", "-q", "/swapfile", "/etc/fstab"], {
+      run(["grep", "-qE", "^[[:space:]]*/swapfile[[:space:]]", "/etc/fstab"], {
         ignoreError: true,
         suppressOutput: true,
       }).status === 0;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const existingFstabEntry =
run(["grep", "-q", "/swapfile", "/etc/fstab"], {
ignoreError: true,
suppressOutput: true,
}).status === 0;
if (!existingFstabEntry) {
runCapture(["sudo", "tee", "-a", "/etc/fstab"], {
ignoreError: false,
input: "/swapfile none swap sw 0 0\n",
});
const existingFstabEntry =
run(["grep", "-qE", "^[[:space:]]*/swapfile[[:space:]]", "/etc/fstab"], {
ignoreError: true,
suppressOutput: true,
}).status === 0;
if (!existingFstabEntry) {
runCapture(["sudo", "tee", "-a", "/etc/fstab"], {
ignoreError: false,
input: "/swapfile none swap sw 0 0\n",
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/preflight.ts` around lines 715 - 724, The current grep call in
existingFstabEntry uses a plain substring search which can match commented lines
or unrelated paths; update the check so it only matches active (non-commented)
fstab entries for /swapfile by changing the command invoked by run([...]) to use
an anchored regex (e.g., grep -qE with a pattern like
'^[[:space:]]*[^#].*/swapfile\b') so only uncommented lines containing /swapfile
are detected; keep the subsequent runCapture([... "sudo", "tee", "-a",
"/etc/fstab"]) logic unchanged so the append happens only when no active entry
exists.

Comment thread test/argv-callers.test.ts
@@ -0,0 +1,123 @@
import { afterEach, describe, expect, it, vi } from "vitest";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add the required SPDX header to this new test file.

This file is missing the repository-mandated license header. As per coding guidelines, **/*.{js,mjs,ts,tsx,sh,md}: Every source file must include an SPDX license header: // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. and // SPDX-License-Identifier: Apache-2.0.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/argv-callers.test.ts` at line 1, Add the required SPDX header lines to
the top of this test file (above the existing import { afterEach, describe,
expect, it, vi } from "vitest"; line): insert the exact comment lines "//
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All
rights reserved." and "// SPDX-License-Identifier: Apache-2.0" as the first two
lines of the file.

Comment thread test/argv-callers.test.ts Outdated
@WilliamK112
WilliamK112 force-pushed the security/argv-callers branch from 2f20e7d to 69dc6a9 Compare April 25, 2026 05:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (3)
src/lib/preflight.ts (1)

715-725: ⚠️ Potential issue | 🟡 Minor

Tighten the /swapfile match before skipping the append.

Line 716 still uses a plain substring grep, so a commented entry or an unrelated path containing /swapfile will make existingFstabEntry look true. In that case the swapfile works for the current boot, but it will not persist across reboot.

Suggested fix
     const existingFstabEntry =
-      run(["grep", "-q", "/swapfile", "/etc/fstab"], {
+      run(["grep", "-qE", "^[[:space:]]*/swapfile[[:space:]]", "/etc/fstab"], {
         ignoreError: true,
         suppressOutput: true,
       }).status === 0;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/preflight.ts` around lines 715 - 725, The current check using
run(["grep", "-q", "/swapfile", "/etc/fstab"]) can be fooled by commented lines
or other paths containing "/swapfile"; change the existence test (the
existingFstabEntry assignment) to search for a non-commented fstab entry that
lists /swapfile as the swap file (e.g., a regex like
'^[[:space:]]*[^#].*\s+/swapfile(\s|$)' or equivalent) so only active fstab
entries match, then keep the append logic using
runCapture(["sudo","tee","-a","/etc/fstab"]) unchanged; update the grep
invocation inside run(...) that sets existingFstabEntry (and any related
variable) to use the stricter pattern.
test/argv-callers.test.ts (2)

3-123: ⚠️ Potential issue | 🟠 Major

Convert this suite from CommonJS loading/cache mutation to ESM + Vitest-native module control.

Lines 3-123 use require.resolve, require, and require.cache, which violates the test/ ESM rule and makes module lifecycle handling brittle. Use await import(...), vi.resetModules(), and vi.mock(...) instead.

Refactor sketch (ESM-compatible)
-const preflightPath = require.resolve("../dist/lib/preflight.js");
-const onboardPath = require.resolve("../dist/lib/onboard.js");
-const runnerPath = require.resolve("../dist/lib/runner.js");
+const preflightPath = "../dist/lib/preflight.js";
+const onboardPath = "../dist/lib/onboard.js";
+const runnerPath = "../dist/lib/runner.js";

 afterEach(() => {
   vi.restoreAllMocks();
-  delete require.cache[preflightPath];
-  delete require.cache[onboardPath];
-  delete require.cache[runnerPath];
+  vi.resetModules();
 });

-it("assessHost uses argv commands for host probes", () => {
+it("assessHost uses argv commands for host probes", async () => {
   const seen: Array<string | readonly string[]> = [];
-  delete require.cache[preflightPath];
-  const preflight = require(preflightPath);
+  const preflight = await import(preflightPath);
  ...
 });

-it("probeContainerDns defaults to argv docker run", () => {
+it("probeContainerDns defaults to argv docker run", async () => {
   const seen: Array<string | readonly string[]> = [];
-  delete require.cache[preflightPath];
-  const { probeContainerDns } = require(preflightPath);
+  const { probeContainerDns } = await import(preflightPath);
  ...
 });

-it("getDockerBridgeGatewayIp uses argv docker inspect", () => {
-  delete require.cache[preflightPath];
-  const { getDockerBridgeGatewayIp } = require(preflightPath);
+it("getDockerBridgeGatewayIp uses argv docker inspect", async () => {
+  const { getDockerBridgeGatewayIp } = await import(preflightPath);
  ...
 });

-it("getGatewayClusterContainerState uses argv docker inspect", () => {
-  const actualRunner = require(runnerPath);
+it("getGatewayClusterContainerState uses argv docker inspect", async () => {
   const runCapture = vi.fn(() => "running healthy\n");
-  require.cache[runnerPath] = { ... } as any;
+  vi.mock(runnerPath, async () => {
+    const actualRunner = await vi.importActual<Record<string, unknown>>(runnerPath);
+    return { ...actualRunner, runCapture };
+  });

-  delete require.cache[onboardPath];
-  const onboard = require(onboardPath);
+  const onboard = await import(onboardPath);
   const state = onboard.getGatewayClusterContainerState();
  ...
 });
#!/bin/bash
# Verify CommonJS-only patterns are still present in this test file.
rg -n -C2 'require\.resolve\(|\brequire\(|require\.cache' test/argv-callers.test.ts

As per coding guidelines, test/**/*.{js,ts}: test/ directory must use ESM (import/export) for test files and test/**/*.test.{js,ts}: Root-level integration tests in test/ directory should use ESM imports and mock external dependencies without calling real NVIDIA APIs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/argv-callers.test.ts` around lines 3 - 123, The tests use CommonJS
require/require.cache and require.resolve (preflightPath/onboardPath/runnerPath)
which violates ESM test rules; replace all require.resolve/require/require.cache
mutations with dynamic ESM imports (await import(...)) and use Vitest module
helpers: call vi.resetModules() in afterEach, replace manual cache stubs with
vi.mock(...) to override runner.runCapture when testing
getGatewayClusterContainerState, and when importing preflight functions
(assessHost, probeContainerDns, getDockerBridgeGatewayIp) import them via await
import and pass mocked implementations (runCaptureImpl/readFileImpl) rather than
mutating require.cache; ensure probeContainerDns and getDockerBridgeGatewayIp
assertions still inspect the array commands and options, and remove any use of
delete require.cache and require.resolve.

1-1: ⚠️ Potential issue | 🟠 Major

Add the required SPDX header to this test file.

Line 1 starts directly with imports; the mandatory SPDX copyright and license lines are missing.

Proposed fix
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
 import { afterEach, describe, expect, it, vi } from "vitest";

As per coding guidelines, **/*.{js,mjs,ts,tsx,sh,md}: Every source file must include an SPDX license header: // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. and // SPDX-License-Identifier: Apache-2.0.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/argv-callers.test.ts` at line 1, This file is missing the mandatory SPDX
header; add the two required comment lines immediately above the first import
statement (the line starting with "import { afterEach, describe, expect, it, vi
}"): "// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION &
AFFILIATES. All rights reserved." and "// SPDX-License-Identifier: Apache-2.0",
ensuring they are the very first lines in the file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/lib/preflight.ts`:
- Around line 715-725: The current check using run(["grep", "-q", "/swapfile",
"/etc/fstab"]) can be fooled by commented lines or other paths containing
"/swapfile"; change the existence test (the existingFstabEntry assignment) to
search for a non-commented fstab entry that lists /swapfile as the swap file
(e.g., a regex like '^[[:space:]]*[^#].*\s+/swapfile(\s|$)' or equivalent) so
only active fstab entries match, then keep the append logic using
runCapture(["sudo","tee","-a","/etc/fstab"]) unchanged; update the grep
invocation inside run(...) that sets existingFstabEntry (and any related
variable) to use the stricter pattern.

In `@test/argv-callers.test.ts`:
- Around line 3-123: The tests use CommonJS require/require.cache and
require.resolve (preflightPath/onboardPath/runnerPath) which violates ESM test
rules; replace all require.resolve/require/require.cache mutations with dynamic
ESM imports (await import(...)) and use Vitest module helpers: call
vi.resetModules() in afterEach, replace manual cache stubs with vi.mock(...) to
override runner.runCapture when testing getGatewayClusterContainerState, and
when importing preflight functions (assessHost, probeContainerDns,
getDockerBridgeGatewayIp) import them via await import and pass mocked
implementations (runCaptureImpl/readFileImpl) rather than mutating
require.cache; ensure probeContainerDns and getDockerBridgeGatewayIp assertions
still inspect the array commands and options, and remove any use of delete
require.cache and require.resolve.
- Line 1: This file is missing the mandatory SPDX header; add the two required
comment lines immediately above the first import statement (the line starting
with "import { afterEach, describe, expect, it, vi }"): "//
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All
rights reserved." and "// SPDX-License-Identifier: Apache-2.0", ensuring they
are the very first lines in the file.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 16eda3cd-80f5-4977-ad92-1b99f1e7516d

📥 Commits

Reviewing files that changed from the base of the PR and between 2f20e7d and 69dc6a9.

📒 Files selected for processing (3)
  • src/lib/onboard.ts
  • src/lib/preflight.ts
  • test/argv-callers.test.ts

@wscurran wscurran added security refactor PR restructures code without intended behavior change labels Apr 27, 2026
@wscurran

Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this pull request that proposes a way to improve security by using argv for host-side helper calls, specifically converting shell-string helper calls to argv-style execution where the command does not actually need a shell.


Related open issues:

@WilliamK112

Copy link
Copy Markdown
Contributor Author

Correcting my previous malformed comment due to shell quoting.

Addressed the ESM test feedback in test/argv-callers.test.ts.

  • replaced require.resolve() / require() / require.cache with ESM-friendly await import(...) + vi.resetModules()
  • kept the preflight argv assertions as runtime tests
  • changed the gateway container-state check to verify the compiled onboard output uses the argv-style runCapture([...]) callsite, which avoids depending on CommonJS cache mutation in the test suite

Also re-ran npm test -- test/argv-callers.test.ts locally, passing 4/4.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
test/argv-callers.test.ts (1)

36-53: Tighten the stub fallback so unexpected commands fail fast.

At Line 52, the fallback returns "" in both branches, so new/unexpected probes can pass silently and weaken this regression test.

Suggested refactor
       runCaptureImpl: (
         command: string | readonly string[],
         options?: { ignoreError?: boolean },
       ) => {
         seen.push(command);
         const key = Array.isArray(command) ? command.join(" ") : command;
@@
-        return options?.ignoreError ? "" : "";
+        if (options?.ignoreError) return "";
+        throw new Error(`unexpected command in test stub: ${key}`);
       },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/argv-callers.test.ts` around lines 36 - 53, The stubbed runCaptureImpl
currently returns an empty string for both branches of the fallback, so
unexpected commands slip through; change the fallback in runCaptureImpl to
return an empty string only when options?.ignoreError is true and otherwise
throw an Error (or otherwise fail) with the unexpected command (use the key
variable) so tests fail fast when a new/unexpected probe is invoked; reference
runCaptureImpl, seen, key and options?.ignoreError to locate and implement this
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/argv-callers.test.ts`:
- Around line 36-53: The stubbed runCaptureImpl currently returns an empty
string for both branches of the fallback, so unexpected commands slip through;
change the fallback in runCaptureImpl to return an empty string only when
options?.ignoreError is true and otherwise throw an Error (or otherwise fail)
with the unexpected command (use the key variable) so tests fail fast when a
new/unexpected probe is invoked; reference runCaptureImpl, seen, key and
options?.ignoreError to locate and implement this behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: af50b030-3d7a-4c0a-96d0-992de3ebf751

📥 Commits

Reviewing files that changed from the base of the PR and between 69dc6a9 and bac60ab.

📒 Files selected for processing (1)
  • test/argv-callers.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
test/argv-callers.test.ts (1)

1-2: ⚠️ Potential issue | 🟠 Major

Add the required SPDX license header at the top of this file.

This new *.ts source file is missing the mandatory SPDX header.

Proposed fix
+// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
 import fs from "node:fs";
 import { afterEach, describe, expect, it, vi } from "vitest";

As per coding guidelines: **/*.{js,mjs,ts,tsx,sh,md}: Every source file must include an SPDX license header.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/argv-callers.test.ts` around lines 1 - 2, Add the required SPDX license
header as the very first line of the file (above any imports like the existing
"import fs from 'node:fs';" and "import { afterEach, describe, expect, it, vi }
from 'vitest';") — e.g. add a single-line comment such as "//
SPDX-License-Identifier: MIT" (or the project's approved identifier) to satisfy
the repository's linting/license rule.
🧹 Nitpick comments (1)
test/argv-callers.test.ts (1)

101-108: Also assert ignoreError: true in the gateway inspect callback test.

This test currently validates argv shape but not the options object. Adding the option assertion will better lock the intended contract.

Proposed hardening
-    const gateway = getDockerBridgeGatewayIp((command: string | readonly string[]) => {
+    const gateway = getDockerBridgeGatewayIp((
+      command: string | readonly string[],
+      opts?: { ignoreError?: boolean },
+    ) => {
       seen.push(command);
+      expect(opts?.ignoreError).toBe(true);
       return "172.17.0.1fd00:abcd::1\n";
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/argv-callers.test.ts` around lines 101 - 108, The test should also
assert that the options object includes ignoreError: true when
getDockerBridgeGatewayIp invokes the docker inspect callback; update the test's
mock callback signature (the function passed into getDockerBridgeGatewayIp) to
accept (command, options), assert/options.ignoreError === true (or deep-equal {
ignoreError: true } depending on how options is structured), and still push the
command to seen; ensure you reference the existing getDockerBridgeGatewayIp test
callback so the assertion is added within that mock rather than a separate
check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@test/argv-callers.test.ts`:
- Around line 1-2: Add the required SPDX license header as the very first line
of the file (above any imports like the existing "import fs from 'node:fs';" and
"import { afterEach, describe, expect, it, vi } from 'vitest';") — e.g. add a
single-line comment such as "// SPDX-License-Identifier: MIT" (or the project's
approved identifier) to satisfy the repository's linting/license rule.

---

Nitpick comments:
In `@test/argv-callers.test.ts`:
- Around line 101-108: The test should also assert that the options object
includes ignoreError: true when getDockerBridgeGatewayIp invokes the docker
inspect callback; update the test's mock callback signature (the function passed
into getDockerBridgeGatewayIp) to accept (command, options),
assert/options.ignoreError === true (or deep-equal { ignoreError: true }
depending on how options is structured), and still push the command to seen;
ensure you reference the existing getDockerBridgeGatewayIp test callback so the
assertion is added within that mock rather than a separate check.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 0d564ec9-f142-4f3e-84e0-58b990170544

📥 Commits

Reviewing files that changed from the base of the PR and between bac60ab and 7d5a678.

📒 Files selected for processing (1)
  • test/argv-callers.test.ts

@ericksoa

ericksoa commented May 1, 2026

Copy link
Copy Markdown
Contributor

Thanks for the contribution here. I am marking this PR as superseded rather than merging it, because later merged work covered the same security objective at a broader layer.

Relevant merged PRs:

Those changes mean current main rejects shell strings for run/runInteractive/runCapture and rejects shell: true on argv helper calls, with intentional shell behavior isolated behind explicit runShell usage. Closing this as superseded.

@ericksoa ericksoa closed this May 1, 2026
@wscurran wscurran added area: ci CI workflows, checks, release automation, or GitHub Actions area: cli Command line interface, flags, terminal UX, or output chore Build, CI, dependency, or tooling maintenance and removed priority: high labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci CI workflows, checks, release automation, or GitHub Actions area: cli Command line interface, flags, terminal UX, or output chore Build, CI, dependency, or tooling maintenance refactor PR restructures code without intended behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants