Skip to content

fix(router): verify shutdown convergence - #7663

Merged
cv merged 18 commits into
NVIDIA:mainfrom
HOYALIM:codex/model-router-verified-stop
Aug 13, 2026
Merged

fix(router): verify shutdown convergence#7663
cv merged 18 commits into
NVIDIA:mainfrom
HOYALIM:codex/model-router-verified-stop

Conversation

@HOYALIM

@HOYALIM HOYALIM commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Make Model Router replacement fail closed unless shutdown converges. NemoClaw validates the recorded process before SIGTERM, requires the recorded PID to stop reporting as running and the health endpoint to stop returning HTTP 2xx, and refuses replacement when either condition is not met. The session stores a numeric PID, so ownership validation and SIGTERM delivery remain separate OS operations.

Changes

  • Verify that the recorded PID runs the expected model-router proxy command for the configured port before SIGTERM.
  • If the recorded PID does not report as running, return only when the health endpoint is not healthy.
  • After SIGTERM, require both process and endpoint convergence before starting a replacement.
  • Never send PID-based SIGKILL without a PID-stable handle.
  • Report signal-delivery, ownership, process, and endpoint failures instead of treating them as shutdown success.
  • Add coverage for initial process state, graceful convergence, signal failure, ownership drift, PID reuse, surviving process or endpoint state, and durable session preservation.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification: the change tightens an internal process-lifecycle invariant without changing commands, options, configuration, defaults, successful onboarding steps, or a documented Model Router setup claim.
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: Codex Desktop completed the nine-category review at 07faa39e86286a07a5813d041c82c25e334120d5. Eight categories pass. System Security has one nonblocking warning: numeric-PID ownership validation and SIGTERM delivery are separate OS operations, so PID reuse can redirect SIGTERM without a PID-stable handle. This interval predates the PR. The change removes PID-based SIGKILL, fails closed when shutdown does not converge, and adds negative-path tests.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: no-docs-needed
  • Evidence: Independent review: PASS — Model Router shutdown remains fail closed without changing its documented contract, and the CI staging comment and assertion identify the exact libssh2 source mismatch.
  • Agent: Codex Desktop documentation writer

DGX Station Hardware Evidence

  • Tested on DGX Station
  • Tested commit:
  • Station profile/scenario:
  • Result:
  • Supporting evidence:

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, and npm run validate:pr passed after refreshing origin/main
  • Targeted behavior tests pass for the current change set — npx vitest run --project cli src/lib/onboard/model-router-process.test.ts src/lib/onboard/model-router.test.ts src/lib/onboard/model-router-python.test.ts src/lib/onboard/routed-inference.test.ts src/lib/onboard/runtime-control-flow.test.ts (54 passed)
  • Applicable broad gate passed — npm run validate:pr; npm --prefix nemoclaw run build; npm run build:cli
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Ho Lim subhoya@gmail.com

Copilot AI review requested due to automatic review settings July 27, 2026 22:25
@copy-pr-bot

copy-pr-bot Bot commented Jul 27, 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.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

stopModelRouterProcess now uses injectable shutdown dependencies, validates PID ownership, checks process and endpoint state, escalates from SIGTERM to SIGKILL, and throws explicit errors. Tests cover successful shutdown and failure cases.

Changes

Model-router shutdown

Layer / File(s) Summary
Injected shutdown control and convergence
src/lib/onboard/model-router-process.ts
Adds StopModelRouterProcessDeps and updates shutdown handling to validate ownership, poll process and endpoint state, escalate signals, and report failures.
Shutdown scenario coverage
src/lib/onboard/model-router-process.test.ts
Adds tests for graceful shutdown, ownership validation, signal errors, SIGKILL escalation, ownership changes, and incomplete convergence.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant stopModelRouterProcess
  participant HealthEndpoint
  participant ProcessState
  participant SignalDelivery
  Caller->>stopModelRouterProcess: stop PID on port
  stopModelRouterProcess->>ProcessState: verify PID owns router port
  stopModelRouterProcess->>HealthEndpoint: check endpoint health
  stopModelRouterProcess->>SignalDelivery: send SIGTERM
  stopModelRouterProcess->>ProcessState: poll PID state
  stopModelRouterProcess->>HealthEndpoint: poll endpoint state
  stopModelRouterProcess->>SignalDelivery: send SIGKILL if needed
  stopModelRouterProcess-->>Caller: resolve or throw shutdown error
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: verifying Model Router shutdown convergence.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — No blocking findings reported

Advisor assessment: No blocking advisor findings reported
Next action: Review the warnings below.
Findings: 0 blockers · 1 warning · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 0 blockers · 1 warning · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 0 blockers · 1 warning · 0 suggestions
  • Model comparison: normalized findings differ; normalized terminology decisions differ; normalized E2E selections differ; severity counts match.
2 terminology differences from the second opinion

Advisory only. These are normalized differences from the primary terminology receipt.

  • PID-stable handle at src/lib/onboard/model-router-process.ts:132: primary classified it as define; the second opinion classified it as justified.
  • PID-based SIGKILL at src/lib/onboard/model-router-process.ts:194: selected only by the second-opinion lane as justified.
2 additional E2E selections from the second opinion

Advisory only. The primary lane did not select these E2E jobs or targets.

  • onboard-managed-image-buildless-e2e: The completed second-opinion lane identified E2E coverage that the primary lane omitted.
  • model-router-provider-routed-inference: The completed second-opinion lane identified E2E coverage that the primary lane omitted.

Second-opinion terminology and E2E selections are advisory. Live E2E does not run automatically for pull requests.

1 semantic terminology decision

Terminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.

  • define — PID-stable handle at src/lib/onboard/model-router-process.ts:132: Define the OS property at first use, or use an established repository term if one names the same identity-preserving reference.

E2E guidance

Advisory only. A maintainer can dispatch the default E2E suite for the commit under review.

Recommended E2E: None

Manual-only E2E: managed-image-multiarch-startup, onboard-repair, onboard-resume, cloud-onboard
The manual PR workflow does not run these selectors for the commit under review. Run them from reviewed code on main.

1 optional E2E recommendation
  • managed-image-protected-runtime
1 warning · 0 suggestions

Warnings

Warnings do not block.

PRA-1 Warning — Prevent PID reuse between ownership validation and SIGTERM

  • Location: src/lib/onboard/model-router-process.ts:163
  • Category: security
  • Problem: The shutdown path validates a numeric PID and then sends SIGTERM in a separate operation. The operating system can reuse that PID during this interval, so SIGTERM can target an unrelated process.
  • Impact: An unrelated host process can receive SIGTERM during an agent transition or router replacement.
  • Recommendation: Use a supported identity-preserving process handle for validation and termination, or avoid signaling when the platform cannot provide one.
  • Verification: Inspect the process-control API used by the supported host platforms and confirm that the same identity-preserving handle is checked and terminated atomically or cannot be reused.
  • Test coverage: Add a process-control regression test that simulates identity replacement between validation and termination and proves the replacement process receives no signal.
  • Simplification (native): Remove Numeric PID ownership rechecks that cannot close the validation-to-signal interval.; use Use a native identity-preserving process-control mechanism where the supported platform provides one.. Net: 0 lines.
  • Keep: Do not remove command-line and port ownership validation until the replacement preserves process identity across termination.
  • Evidence: src/lib/onboard/model-router-process.ts:129-132 documents that validation and SIGTERM delivery are separate operations and PID reuse can redirect SIGTERM. src/lib/onboard/model-router-process.ts:153-163 validates ownership before calling `kill(pid, "SIGTERM")`. src/lib/onboard/model-router-process.test.ts:151-207 covers SIGKILL refusal but does not make the SIGTERM operation identity-preserving.

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

@HOYALIM
HOYALIM force-pushed the codex/model-router-verified-stop branch from 035e31f to ddcc793 Compare July 27, 2026 22:29
Copilot AI review requested due to automatic review settings July 27, 2026 22:29

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@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 (3)
src/lib/onboard/model-router-process.ts (2)

176-190: 🔒 Security & Privacy | 🔵 Trivial

Residual PID-reuse window remains between the ownership recheck and the signal call.

Rechecking ownership right before SIGKILL substantially narrows the PID-reuse race this PR targets, but since doesModelRouterProcessOwnPort and kill() are two separate OS syscalls, there is no true atomicity guarantee — the OS could still reap and reuse the PID in the (very small) gap between them. Worth noting as a known residual limitation of PID+signal-based shutdown; a fully atomic guarantee would require something like Linux pidfd-based signaling, which is likely out of scope here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard/model-router-process.ts` around lines 176 - 190, Document the
residual PID-reuse limitation in the shutdown flow after the
doesModelRouterProcessOwnPort recheck and before SIGKILL: ownership validation
and kill remain separate syscalls, so they cannot provide atomic protection
against PID reuse. Note that pidfd-based signaling would be required for a fully
atomic guarantee, while keeping the existing behavior unchanged.

160-205: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared "send signal, then poll for convergence" logic.

The SIGTERM block (161-174) and SIGKILL block (192-205) are near-identical: try/catch around kill() that checks convergence on failure, then a sleep+convergence poll loop, differing only in the signal and attempt count. Extracting a small helper reduces duplication in an already flagged high-complexity function.

♻️ Proposed helper extraction
+async function signalAndAwaitConvergence(
+  pid: number,
+  port: number,
+  signal: NodeJS.Signals,
+  attempts: number,
+  { isRunning, isHealthy, kill, sleep }: {
+    isRunning: (pid: number) => boolean;
+    isHealthy: (port: number, timeoutMs?: number) => Promise<boolean>;
+    kill: (pid: number, signal: NodeJS.Signals) => void;
+    sleep: (delayMs: number) => Promise<void>;
+  },
+): Promise<boolean> {
+  try {
+    kill(pid, signal);
+  } catch (error) {
+    if (!isRunning(pid) && !(await isHealthy(port, 1000))) return true;
+    throw new Error(
+      `Failed to send ${signal} to model router PID ${pid}: ${
+        error instanceof Error ? error.message : String(error)
+      }`,
+    );
+  }
+  for (let _attempt = 0; _attempt < attempts; _attempt++) {
+    await sleep(500);
+    if (!isRunning(pid) && !(await isHealthy(port, 1000))) return true;
+  }
+  return false;
+}
+
-  try {
-    kill(pid, "SIGTERM");
-  } catch (error) {
-    if (!isRunning(pid) && !(await isHealthy(port, 1000))) return;
-    throw new Error(
-      `Failed to send SIGTERM to model router PID ${pid}: ${
-        error instanceof Error ? error.message : String(error)
-      }`,
-    );
-  }
-  for (let _attempt = 0; _attempt < 10; _attempt++) {
-    await sleep(500);
-    if (!isRunning(pid) && !(await isHealthy(port, 1000))) return;
-  }
+  if (await signalAndAwaitConvergence(pid, port, "SIGTERM", 10, { isRunning, isHealthy, kill, sleep }))
+    return;

Apply the same substitution to the SIGKILL block with attempts = 5.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard/model-router-process.ts` around lines 160 - 205, Extract the
duplicated signal-and-poll flow from the shutdown function into a helper that
accepts the PID, port, signal, and poll-attempt count. Preserve the existing
kill-error convergence checks and error messages, then replace the SIGTERM block
with 10 attempts and the SIGKILL block with 5 attempts while keeping the
ownership validation between them.
src/lib/onboard/model-router-process.test.ts (1)

71-192: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the untested fail-closed branches.

This suite covers ownership drift, SIGTERM failure, and SIGKILL escalation well, but two safety-relevant branches in stopModelRouterProcess have no direct test:

  • The initial !isRunning(pid) fork (source lines 144-149): neither "already stopped + port also unhealthy → silent success" nor "already stopped + port still healthy → refuse to replace" is exercised.
  • A SIGKILL-stage signal-delivery failure (source lines 194-201), mirroring the existing SIGTERM EPERM test at Lines 107-119.

Since these are exactly the "explicit shutdown failure" guarantees called out in the PR objectives, adding tests here protects against silent regressions.

✅ Example additional test cases
it("returns immediately when the process is already gone and the port is unhealthy", async () => {
  await expect(
    stopModelRouterProcess(123, 4000, {
      isRunning: () => false,
      readCommandLine: () => ROUTER_ARGS,
      isHealthy: async () => false,
      kill: () => {},
      sleep: async () => {},
    }),
  ).resolves.toBeUndefined();
});

it("refuses to replace when the process is gone but the port is still healthy", async () => {
  await expect(
    stopModelRouterProcess(123, 4000, {
      isRunning: () => false,
      readCommandLine: () => ROUTER_ARGS,
      isHealthy: async () => true,
      kill: () => {},
      sleep: async () => {},
    }),
  ).rejects.toThrow("remains healthy");
});

it("fails closed when SIGKILL cannot be delivered", async () => {
  await expect(
    stopModelRouterProcess(123, 4000, {
      isRunning: () => true,
      readCommandLine: () => ROUTER_ARGS,
      isHealthy: async () => true,
      kill: (_pid, signal) => {
        if (signal === "SIGKILL") throw new Error("EPERM");
      },
      sleep: async () => {},
    }),
  ).rejects.toThrow("Failed to send SIGKILL");
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/onboard/model-router-process.test.ts` around lines 71 - 192, Add
direct tests in the stopModelRouterProcess suite for both initial !isRunning
outcomes: resolve when the endpoint is unhealthy and reject when it remains
healthy. Also add a SIGKILL-stage delivery failure test using the existing
owned-process setup, making kill throw only for SIGKILL and asserting the
“Failed to send SIGKILL” error.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/lib/onboard/model-router-process.test.ts`:
- Around line 71-192: Add direct tests in the stopModelRouterProcess suite for
both initial !isRunning outcomes: resolve when the endpoint is unhealthy and
reject when it remains healthy. Also add a SIGKILL-stage delivery failure test
using the existing owned-process setup, making kill throw only for SIGKILL and
asserting the “Failed to send SIGKILL” error.

In `@src/lib/onboard/model-router-process.ts`:
- Around line 176-190: Document the residual PID-reuse limitation in the
shutdown flow after the doesModelRouterProcessOwnPort recheck and before
SIGKILL: ownership validation and kill remain separate syscalls, so they cannot
provide atomic protection against PID reuse. Note that pidfd-based signaling
would be required for a fully atomic guarantee, while keeping the existing
behavior unchanged.
- Around line 160-205: Extract the duplicated signal-and-poll flow from the
shutdown function into a helper that accepts the PID, port, signal, and
poll-attempt count. Preserve the existing kill-error convergence checks and
error messages, then replace the SIGTERM block with 10 attempts and the SIGKILL
block with 5 attempts while keeping the ownership validation between them.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4982b810-680b-4b52-bac7-eafcca4a7042

📥 Commits

Reviewing files that changed from the base of the PR and between fbfbe68 and 035e31f.

📒 Files selected for processing (2)
  • src/lib/onboard/model-router-process.test.ts
  • src/lib/onboard/model-router-process.ts

@wscurran wscurran added area: routing Request routing, policy routing, model selection, or fallback logic bug-fix PR fixes a bug or regression labels Jul 28, 2026
@prekshivyas prekshivyas self-assigned this Aug 3, 2026
@HOYALIM

HOYALIM commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

@cv @NVIDIA/nemoclaw-maintainer Could you please help with the protected E2E disposition for exact head ddcc793?

  • The ordinary reported checks are green.
  • There are no active non-outdated review threads or exact-head human change requests.
  • E2E / PR Gate failed only after timing out for roughly six hours while waiting for the trusted verdict from coordination run 90126097918.

I cannot authorize or repair that trusted-run path from the fork. I will keep this head unchanged so checks are not reset again. Please either authorize/retrigger the repository-supported E2E path for this exact head, identify any remaining code or evidence blocker I can address, or mark the PR superseded if its outcome is no longer wanted.

@apurvvkumaria apurvvkumaria left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed exact head ddcc793. The shutdown path now verifies router ownership, waits for both PID and endpoint convergence, rechecks ownership before escalation, and reports non-convergence. I found no blocking defect. Non-blocking fast follow: address the existing advisor warning with a narrowly scoped identity-stable signaling design for the check-to-signal PID-reuse window. This PR materially improves the prior unconditional numeric-PID signaling behavior. The failed E2E gate is a trusted-verdict timeout, not an attributable test failure.

Signed-off-by: Ho Lim <subhoya@gmail.com>
@HOYALIM
HOYALIM force-pushed the codex/model-router-verified-stop branch from ddcc793 to b269a48 Compare August 4, 2026 08:18

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed commit 1fe5650bf. The ownership check at the start of stopModelRouterProcess is already the check immediately preceding SIGTERM; inserting another command-line read before the next syscall would not close the PID-reuse interval. A fully atomic guarantee requires an identity-stable primitive such as Linux pidfd signaling, which is a separate platform design. I therefore do not treat Advisor finding PRA-1 as a defect introduced by this change. The SIGKILL path correctly rechecks after the grace interval, and tests cover ownership drift, signal failure, surviving PID, surviving endpoint, and convergence.

The maintainer update from main is complete and CI is running for this commit. Approval waits for all required checks and a refreshed documentation-writer receipt. The receipt currently names an older commit and leaves its completion checkbox clear.

Signed-off-by: Ho Lim <subhoya@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

cv
cv previously requested changes Aug 7, 2026

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The SIGKILL escalation still has a PID-reuse race. Ownership is read and kill(pid, SIGKILL) occurs in a separate operation, so an unrelated process can receive the recycled PID after the final check. Use a PID-stable process handle where supported, or do not escalate when ownership cannot be made atomic. Add a regression that changes the owner between final validation and escalation and proves no signal reaches the replacement process. Refresh onto current main and rerun required and E2E checks.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

cv
cv previously requested changes Aug 7, 2026

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Additionally, please review this PR description and diff for comms and documentation guidelines in WRITING.md and linked artifacts.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
@prekshivyas

Copy link
Copy Markdown
Collaborator

Addressed the PID-reuse escalation review at exact head bb05666 (fix commit 8dec1d6, followed by the current-main merge).

The session stores only a numeric PID, so the stop path now sends SIGTERM and verifies PID plus endpoint convergence. If the process survives, it fails closed and does not send SIGKILL. This removes the non-atomic check-to-signal window instead of documenting it as residual risk.

The new regression changes ownership immediately after the final command-line observation and proves the replacement receives no signal. Existing cases still cover initial ownership rejection, SIGTERM delivery failure, graceful convergence, ownership drift, and a surviving health endpoint.

Validation on the refreshed head:

  • model-router suites: 18/18 passed
  • npm run build:cli: passed
  • root, plugin, JS-config, and CLI TypeScript checks: passed
  • repository hooks and pre-push gates: passed

I also reviewed the changed comment, error text, and test titles against WRITING.md: each names the invariant or observable behavior, uses one shutdown term consistently, and avoids unsupported safety claims. Requesting code and documentation re-review.

@prekshivyas
prekshivyas requested a review from cv August 11, 2026 19:49
@cv

cv commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Security review — latest PR commit 2db7913ffaf1ed9c6be813666ba803f55812e095: PASS with one nonblocking inherited limitation.

  1. Secrets and Credentials — PASS. No credential source, value, storage, or logging path changes.
  2. Input Validation and Data Sanitization — PASS. The recorded PID, expected model-router proxy command, configured port, process state, and health response are validated.
  3. Authentication and Authorization — PASS. Replacement remains bound to the recorded managed process and refuses ownership drift.
  4. Dependencies and Third-Party Libraries — PASS. No dependency changes.
  5. Error Handling and Logging — PASS. Signal failure, ownership drift, surviving process, and surviving endpoint states fail closed with distinct messages; durable session state is preserved.
  6. Cryptography and Data Protection — PASS. No cryptographic or protected-data surface changes.
  7. Configuration and Security Headers — PASS. No configuration, network policy, port default, or header change.
  8. Security Testing — PASS. Tests cover initial state, graceful convergence, signal failure, ownership drift, PID reuse, residual process or endpoint state, and session preservation.
  9. System Security — PASS with a nonblocking inherited limitation. The numeric-PID ownership check and SIGTERM delivery cannot be atomic without a PID-stable OS handle. This interval predates the PR. The change removes PID-based SIGKILL, waits for both PID and endpoint convergence, and refuses replacement when either remains.

No blocking finding remains. Fresh GitHub checks and commit verification are still required before merge.

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed latest PR commit 2db7913ffaf1ed9c6be813666ba803f55812e095. The change verifies the recorded Model Router process, removes PID-based SIGKILL, requires process and health-endpoint convergence, and preserves durable state on failure. The nine-category security review has no blocking finding. Approval remains subject to current required checks and GitHub commit verification.

@cv
cv dismissed stale reviews from themself August 13, 2026 07:03

Dismissed as stale: the latest commit removes PID-based SIGKILL, refuses replacement until both process and endpoint state converge, and adds PID-reuse and failure-path regression coverage.

@cv
cv merged commit 8ba35ab into NVIDIA:main Aug 13, 2026
54 of 57 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: routing Request routing, policy routing, model selection, or fallback logic bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants