Skip to content

fix(blueprint): reload private network cache on file changes#4092

Merged
ericksoa merged 2 commits into
NVIDIA:mainfrom
1PoPTRoN:fix/private-networks-cache-reload
May 26, 2026
Merged

fix(blueprint): reload private network cache on file changes#4092
ericksoa merged 2 commits into
NVIDIA:mainfrom
1PoPTRoN:fix/private-networks-cache-reload

Conversation

@1PoPTRoN

@1PoPTRoN 1PoPTRoN commented May 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Refresh the plugin-side private network blocklist when private-networks.yaml changes during a long-running process. This prevents stale SSRF/private-network validation data while preserving the existing synchronous cache behavior for unchanged files.

Related Issue

Fixes #4091

Changes

  • Track the resolved private-networks.yaml path, mtimeMs, and file size in the cached private network document.
  • Reload the parsed YAML and BlockList when the file metadata changes.
  • Preserve the descriptive missing-file error for absent private-networks.yaml.
  • Avoid an extra cache/stat path in isPrivateHostname() by reusing the loaded BlockList.
  • Add a regression test proving the cache reloads when private-networks.yaml changes without calling resetCache().

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)

Verification

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • make 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)

Additional focused verification run:

  • npm test -- private-networks.test.ts
  • npx biome check nemoclaw/src/blueprint/private-networks.ts nemoclaw/src/blueprint/private-networks.test.ts
  • npm --prefix nemoclaw run build

Signed-off-by: 1PoPTRoN vrxn.arp1traj@gmail.com

Summary by CodeRabbit

  • Bug Fixes
    • Improved private networks loading and caching: reliably reloads when file mtime or size change, reduces frequent metadata checks with short throttling, and returns a clear error if the YAML disappears. Explicit blueprint-path override now skips dev probing.
  • Behavior
    • Private-address checks unified under consolidated blocklist logic, making IP and hostname IP-literal validation more consistent.
  • Tests
    • Added tests covering cache behavior, mtime-only and size-only updates, blueprint-path override, and the disappearing-file error with mocked file metadata and time.

Review Change Stack

Copilot AI review requested due to automatic review settings May 22, 2026 20:58
@copy-pr-bot

copy-pr-bot Bot commented May 22, 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 May 22, 2026

Copy link
Copy Markdown
Contributor

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

The private-networks YAML loader now checks mtimeMs and file size via statSync and stores those stats with the cached BlockList; load() validates stats and reloads when either changes. IP/hostname helpers delegate to shared check helpers. Tests mock fs.statSync and verify no-reload, mtime-reload, size-only-reload, and missing-file-between-stat-and-read scenarios.

Changes

Private Networks Cache Invalidation via File Metadata

Layer / File(s) Summary
Cache metadata structure and error handling
nemoclaw/src/blueprint/private-networks.ts
Module docs updated; statSync imported; LoadedNetworks extended with source, mtimeMs, size, checkedAtMs, STAT_CHECK_INTERVAL_MS, and missingPrivateNetworksError() factory.
File stat-based cache validation and reload
nemoclaw/src/blueprint/private-networks.ts
load() throttles stat checks, calls statSync() to fetch mtimeMs/size, compares against cached values, rebuilds BlockList and normalisedNames on mismatch, and uses centralized ENOENT handling via isNodeEnoent + readPrivateNetworksFile.
Centralized IP/hostname checks
nemoclaw/src/blueprint/private-networks.ts
Added isPrivateIpInBlockList(address, blockList) and routed isPrivateIp() and isPrivateHostname() through the load() result and that helper for consistent IP-family BlockList checks.
Mock filesystem metadata support
nemoclaw/src/blueprint/private-networks.test.ts
Test node:fs mock extended with per-path mtimes and sizes, nextMtime, and Date.now control; statSync returns stats or throws ENOENT.
Test setup and cache reload verification
nemoclaw/src/blueprint/private-networks.test.ts
Helpers to seed/replace YAML (including preserving mtime for size-only updates), beforeEach resets metadata and clocks, asserts no existsSync probing when NEMOCLAW_BLUEPRINT_PATH is set, and tests for missing-file-between-stat-and-read, no-reload within stat interval, reload on mtime change, and reload on size-only change.

🎯 4 (Complex) | ⏱️ ~45 minutes

"🐰
I nibble at mtime and chew on size,
A tiny clock ticks, the cache grows wise—
When files reform and whisper new signs,
I hop and rebuild the blocky lines.
Fresh lists, fresh hops, fresh guarded skies."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% 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 directly and concisely describes the main change: implementing cache reload functionality when private-networks.yaml file changes.
Linked Issues check ✅ Passed The PR comprehensively addresses issue #4091 by tracking file metadata (mtimeMs, size), implementing stat-based cache invalidation, centralizing error handling, and adding regression tests for cache reload behavior.
Out of Scope Changes check ✅ Passed All changes in both files are directly scoped to cache invalidation: test infrastructure for file mocking, metadata tracking, cache reload logic, and helper refactoring for consistent BlockList usage.

✏️ 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.

@1PoPTRoN 1PoPTRoN force-pushed the fix/private-networks-cache-reload branch from a69f4be to 13f4f42 Compare May 22, 2026 20:58

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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates the blueprint private-networks loader to support hot-reloading when the private-networks.yaml file changes, while keeping the SSRF validation behavior consistent.

Changes:

  • Reload node:net BlockList when private-networks.yaml’s file stats change (mtime/size)
  • Refactor IP check logic into a helper to reuse an already-loaded BlockList
  • Extend unit tests and fs mocks to cover the new reload behavior

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
nemoclaw/src/blueprint/private-networks.ts Add stat-based cache invalidation + helper for IP checks using a provided BlockList
nemoclaw/src/blueprint/private-networks.test.ts Update node:fs mock to support statSync and add a test for reload-on-change

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread nemoclaw/src/blueprint/private-networks.ts
Comment thread nemoclaw/src/blueprint/private-networks.ts Outdated
Comment thread nemoclaw/src/blueprint/private-networks.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.

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@nemoclaw/src/blueprint/private-networks.test.ts`:
- Around line 285-297: The regression test "reloads when private-networks.yaml
mtime changes" currently rewrites the YAML with different content length so both
mtime and size change; make the test isolate mtime by ensuring the file size
stays the same when calling seedYaml or by updating only the file mtime instead
of replacing content. Concretely, in the test that calls getPrivateNetworks(),
change seedYaml("/blueprint/private-networks.yaml", ...) so the new YAML payload
is padded to the original byte length (or alternatively replace the seedYaml
call with a touch using fs.utimesSync or a helper that updates mtime only), then
assert that getPrivateNetworks() returns a new object and isPrivateHostname
behaves as expected. Ensure references to getPrivateNetworks(), seedYaml (or the
fs.utimesSync touch), and isPrivateHostname are used so the reload is driven
solely by mtime change.

In `@nemoclaw/src/blueprint/private-networks.ts`:
- Around line 149-162: The code currently translates ENOENT only during statSync
but not during the subsequent readFileSync, so if the file is deleted between
those calls you get a raw fs ENOENT instead of the standardized
missingPrivateNetworksError; update the logic in the private-networks loader
(the block that calls statSync, readFileSync and parseDocument) to catch ENOENT
from the read step as well and rethrow missingPrivateNetworksError(source) (e.g.
wrap the readFileSync + parseDocument call in a try/catch that checks err.code
=== "ENOENT" and throws missingPrivateNetworksError(source)), keeping the
existing cached check and preserving mtimeMs/size behavior.
🪄 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: 0b9cd3d5-73d5-48cd-8773-c017ceb23d77

📥 Commits

Reviewing files that changed from the base of the PR and between 2a78b5e and 13f4f42.

📒 Files selected for processing (2)
  • nemoclaw/src/blueprint/private-networks.test.ts
  • nemoclaw/src/blueprint/private-networks.ts

Comment thread nemoclaw/src/blueprint/private-networks.test.ts
Comment thread nemoclaw/src/blueprint/private-networks.ts Outdated
@1PoPTRoN 1PoPTRoN force-pushed the fix/private-networks-cache-reload branch 3 times, most recently from 9f359e9 to 47874df Compare May 22, 2026 21:23

@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)
nemoclaw/src/blueprint/private-networks.test.ts (1)

329-334: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Isolate the mtime reload test from size changes

On Line 331, the test uses seedYaml(...), which also changes file size via sizes.set(...). That means this case still validates “mtime-or-size changed”, not strictly mtime-driven reload.

Suggested patch
 it("reloads when private-networks.yaml mtime changes", () => {
-  const before = getPrivateNetworks();
-  seedYaml(
-    "/blueprint/private-networks.yaml",
-    "ipv4:\n  - address: 8.8.8.0\n    prefix: 24\n    purpose: after mtime change\nipv6: []\nnames: []\n",
-  );
+  const path = "/blueprint/private-networks.yaml";
+  const before = getPrivateNetworks();
+  const original = store.get(path)!;
+  store.set(path, original.replace("10.0.0.0", "8.8.8.0"));
+  // keep size unchanged so this test isolates mtime-based invalidation
+  sizes.set(path, original.length);
+  mtimes.set(path, (mtimes.get(path) ?? 0) + 1);
   advanceStatInterval();

   const after = getPrivateNetworks();

   expect(after).not.toBe(before);
   expect(isPrivateHostname("8.8.8.1")).toBe(true);
   expect(isPrivateHostname("10.0.0.1")).toBe(false);
 });
🤖 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 `@nemoclaw/src/blueprint/private-networks.test.ts` around lines 329 - 334, The
test "reloads when private-networks.yaml mtime changes" currently uses
seedYaml(...) which also updates the sizes map and therefore validates
mtime-or-size changes; change the test to only modify the file mtime without
altering size: either replace the seedYaml call with a pure-mtime update (e.g.,
fs.utimes/utimesSync or the project's touch helper) for the
"/blueprint/private-networks.yaml" file, or if you must use seedYaml,
immediately restore sizes.set("/blueprint/private-networks.yaml", previousSize)
so that only the mtime differs; keep references to getPrivateNetworks() and the
same file path so the test still asserts reload-on-mtime only.
🤖 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.

Duplicate comments:
In `@nemoclaw/src/blueprint/private-networks.test.ts`:
- Around line 329-334: The test "reloads when private-networks.yaml mtime
changes" currently uses seedYaml(...) which also updates the sizes map and
therefore validates mtime-or-size changes; change the test to only modify the
file mtime without altering size: either replace the seedYaml call with a
pure-mtime update (e.g., fs.utimes/utimesSync or the project's touch helper) for
the "/blueprint/private-networks.yaml" file, or if you must use seedYaml,
immediately restore sizes.set("/blueprint/private-networks.yaml", previousSize)
so that only the mtime differs; keep references to getPrivateNetworks() and the
same file path so the test still asserts reload-on-mtime only.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 732fd618-d208-4dcc-9866-4ff68254c042

📥 Commits

Reviewing files that changed from the base of the PR and between 9f359e9 and 47874df.

📒 Files selected for processing (2)
  • nemoclaw/src/blueprint/private-networks.test.ts
  • nemoclaw/src/blueprint/private-networks.ts

Signed-off-by: 1PoPTRoN <vrxn.arp1traj@gmail.com>
@1PoPTRoN 1PoPTRoN force-pushed the fix/private-networks-cache-reload branch from 47874df to ce140e9 Compare May 25, 2026 10:53
@1PoPTRoN

Copy link
Copy Markdown
Contributor Author

@ericksoa @cv @jyaunches

@wscurran wscurran added enhancement New capability or improvement request fix labels May 26, 2026
@wscurran

Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this detailed PR about refreshing the private network cache on file changes. This proposes a fix for the issue where the cache does not reload when private-networks.yaml changes, and also improves the cache behavior by tracking file metadata and reloading the parsed YAML when the file changes.


Related open issues:

@wscurran wscurran added refactor PR restructures code without intended behavior change Networking labels May 26, 2026

@ericksoa ericksoa 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.

Approved. I reviewed the cache invalidation path against the linked issue and current main. The implementation reloads the plugin-side private network blocklist on source/stat changes while preserving the existing cached fast path and descriptive missing-file handling.

Local validation passed: focused private-networks tests, plugin suite, plugin build, CLI build, SSRF parity test, and a same-size mtime-only reload probe. The remaining CodeRabbit note is test precision rather than a behavior blocker.

@ericksoa ericksoa merged commit b73bac9 into NVIDIA:main May 26, 2026
17 checks passed
@ericksoa ericksoa enabled auto-merge (squash) May 26, 2026 23:29
cv added a commit that referenced this pull request May 27, 2026
## Summary

Refresh NemoClaw documentation and regenerated user skills for the
v0.0.52 release-prep window. Adds the v0.0.52 release-notes entry and
regenerates `nemoclaw-user-*` skills so the published Fern docs and the
agent-skill references stay in sync.

## Source summary

- #4260 -> `docs/about/release-notes.mdx`: Document the OpenClaw runtime
bump to 2026.5.22 and call out the `min_openclaw_version` compatibility
floor versus `OPENCLAW_VERSION` Dockerfile pin. (Architecture and
commands pages were already updated in #4260 itself.)
- #4272 -> `docs/about/release-notes.mdx`: Document the Hermes v0.14
root-entrypoint sandbox layout repair (precreated runtime dirs, sticky
group-writable `/sandbox/.hermes`, removed `gateway.pid` symlink
precreation, legacy state cleanup at launch).
- #4261 -> `docs/about/release-notes.mdx`: Document the onboard ready
output restoration that points users at `nemoclaw <name> dashboard-url
--quiet`.
- #4200 -> `docs/about/release-notes.mdx`: Document Slack token
validation in onboarding so invalid `SLACK_BOT_TOKEN` values trigger a
re-prompt instead of silent advance.
- #4278 -> `docs/about/release-notes.mdx`: Document the Windows
bootstrap regression fix that restores the separate Ubuntu setup handoff
window, keeps `Ubuntu-24.04` as the default distro, and documents
`-DistroName Ubuntu` to reuse an existing distro. (The
`docs/get-started/windows-preparation.mdx` page was already updated in
#4278 itself.)
- #4092 -> `docs/about/release-notes.mdx`: Document the blueprint
private-network blocklist reload when `private-networks.yaml` changes on
disk.
- Release cleanup -> `.agents/skills/nemoclaw-user-*`: Regenerate user
skills with `scripts/docs-to-skills.py docs/ .agents/skills/ --prefix
nemoclaw-user --doc-platform fern-mdx` so the agent-skill references
pick up the v0.0.52 release-notes update plus the WeChat / WhatsApp doc
changes that already landed in #4276.

## Type of Change

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

## Verification

- `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix
nemoclaw-user --doc-platform fern-mdx` -> 10 skills, 1724 lines, 29
reference files.
- `npm run docs` -> 0 errors, 1 warning (Fern check clean).
- `npm run build:cli` -> success (refreshed `dist/` so the pre-push
TypeScript hook passes).
- Skip-list check against `docs/.docs-skip` `skip-terms`: no "permissive
mode", "shields down", "shields up", "shields status", "config
rotate-token", or "rotate-token" strings in `docs/` or generated skills.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Experimental WeChat messaging channel added (QR pairing), alongside
Telegram, Discord, Slack, and WhatsApp.

* **Documentation**
* Updated onboarding, messaging-channel, CLI, and troubleshooting docs
to include WeChat/WhatsApp (marked experimental) and new onboarding
flags/notes.
* Clarified provider validation and runtime routing behavior for
OpenAI-compatible endpoints and Google Gemini.
  * Updated Windows bootstrap/WSL guidance to target Ubuntu 24.04.

* **Chores**
* Added v0.0.52 release notes (runtime upgrade, sandbox hardening,
onboarding and network fixes).

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/NVIDIA/NemoClaw/pull/4293?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Carlos Villela <cvillela@nvidia.com>
@wscurran wscurran added area: networking DNS, proxy, TLS, ports, host aliases, or connectivity bug-fix PR fixes a bug or regression feature PR adds or expands user-visible functionality and removed fix labels Jun 3, 2026
@wscurran wscurran removed enhancement New capability or improvement request refactor PR restructures code without intended behavior change feature PR adds or expands user-visible functionality labels Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: networking DNS, proxy, TLS, ports, host aliases, or connectivity bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Private network blocklist cache does not reload when private-networks.yaml changes

4 participants