Description
nemoclaw <name> policy-list always renders the entire YAML body of the whatsapp preset (network_policies, endpoints, comments, the lot) as if it were that preset's description. Every other preset renders cleanly because their description: lines are double-quoted, which stops the parser's regex at the closing quote. whatsapp.yaml is the only preset whose description: is unquoted, so the regex greedily captures from description: all the way to end-of-file. Result: the policy-list output ends with a confusing dump of WhatsApp's full preset definition (host: web.whatsapp.com, tls: skip, Noise-over-WebSocket comments, etc.), regardless of whether whatsapp is applied to the sandbox.
Two-sided fix: (a) the regex in src/lib/policy/index.ts is fragile and should use a proper YAML parser or at least [^\n]* so unquoted descriptions can't run past end-of-line; (b) quote whatsapp.yaml's description to match the convention used by the other 18 presets.
Environment
Device: a1u2n2g-0096-02 / 10.176.178.129 (Ubuntu 24.04, no GPU)
Also reproduces on 2u2g-gen-0690 / 10.57.211.27 (Ubuntu 24.04, RTX 5090)
OS: Ubuntu 24.04.4 LTS
Architecture: x86_64
Node.js: v22.22.3
npm: 10.9.8
Docker: Docker version 29.4.1, build 055a478
OpenShell CLI: openshell 0.0.44
NemoClaw: nemoclaw v0.0.52
OpenClaw: 2026.4.24 (ollama-base) / 2026.5.22 (cpu-sb, gpu-sb)
Steps to Reproduce
- Have any healthy sandbox with any policy presets applied.
- Run:
nemoclaw <name> policy-list
- Observe the end of the output: a
network_policies: block with the whatsapp preset's YAML body appears, even though whatsapp is NOT applied (its bullet shows ○).
Expected Result
The output ends with the last preset's ○ whatsapp — <description> bullet line. No raw YAML body appears unless a future feature explicitly renders it. (For comparison, every other preset's bullet line is one tidy entry — the whatsapp one is the only one that spills.)
Actual Result
$ nemoclaw ollama-base policy-list
Policy presets for sandbox 'ollama-base':
● brave — Brave Search API access
● brew — Homebrew (Linuxbrew) package manager access (brew binary preinstalled in base image)
○ discord — Discord API, gateway, and CDN access
○ github — GitHub.com and GitHub API access (git)
● huggingface — Hugging Face Hub, LFS, and Inference API access
○ jira — Jira and Atlassian Cloud access
● local-inference — Local inference access (Ollama, vLLM) via host gateway
○ nous-audio — Nous Portal managed audio generation and transcription gateway
[...]
○ whatsapp — WhatsApp Web WebSocket and media access
network_policies:
whatsapp:
name: whatsapp
endpoints:
# WhatsApp Web Noise-over-WebSocket. The /ws/chat upgrade requires
# HTTP/1.1; OpenShell's proxy negotiates h2 ALPN by default when it
# terminates TLS, and Meta's edge returns HTTP/2 405/400 because
# ... (comments continue for many lines)
- host: web.whatsapp.com
port: 443
access: full
tls: skip
- host: "*.web.whatsapp.com"
port: 443
access: full
tls: skip
Code Analysis
1) The parser at src/lib/policy/index.ts:53-71 uses regex on raw YAML:
function listPresets(): PresetInfo[] {
if (!fs.existsSync(PRESETS_DIR)) return [];
return fs
.readdirSync(PRESETS_DIR)
.filter((f: string) => f.endsWith(".yaml"))
.map((f: string) => {
const content = fs.readFileSync(path.join(PRESETS_DIR, f), "utf-8");
const nameMatch = content.match(/^\s*name:\s*(.+)$/m);
const descMatch = content.match(/^\s*description:\s*"?([^"]*)"?$/m); // ← (A)
return {
file: f,
name: nameMatch ? nameMatch[1].trim() : f.replace(".yaml", ""),
description: descMatch ? descMatch[1].trim() : "",
};
});
}
Problem with regex (A): [^"]* is greedy AND matches newlines (negated character classes include \n by default in JavaScript regex). Combined with the /m flag, the regex looks line-anchored but the [^"]* capture group happily spans newlines until it hits a " or EOF. Every preset description is quoted (description: "..."), so capture stops at the closing quote. EXCEPT whatsapp:
nemoclaw-blueprint/policies/presets/whatsapp.yaml (line 5):
preset:
name: whatsapp
description: WhatsApp Web WebSocket and media access # ← UNQUOTED
network_policies:
whatsapp:
name: whatsapp
endpoints:
# ... long block comment ...
- host: web.whatsapp.com
...
With no quotes on the description line, the regex's [^"]* group greedily slurps from "WhatsApp Web..." all the way to the next " in the file — which is the tls: skip block's host: "*.web.whatsapp.com" double quote, several screenfuls down. That captured chunk becomes the "description" rendered to the user.
2) Quoting consistency verified across all 19 preset YAMLs:
| File |
Status |
| brave.yaml |
QUOTED |
| brew.yaml |
QUOTED |
| discord.yaml |
QUOTED |
| github.yaml |
QUOTED |
| huggingface.yaml |
QUOTED |
| jira.yaml |
QUOTED |
| local-inference.yaml |
QUOTED |
| nous-audio.yaml |
QUOTED |
| nous-browser.yaml |
QUOTED |
| nous-code.yaml |
QUOTED |
| nous-image.yaml |
QUOTED |
| nous-web.yaml |
QUOTED |
| npm.yaml |
QUOTED |
| outlook.yaml |
QUOTED |
| pypi.yaml |
QUOTED |
| slack.yaml |
QUOTED |
| telegram.yaml |
QUOTED |
| wechat.yaml |
QUOTED |
| whatsapp.yaml |
UNQUOTED ← the only one |
(Generated with a one-shot grep across nemoclaw-blueprint/policies/presets/*.yaml.)
3) Renderer at src/lib/actions/sandbox/policy-channel.ts:231-270:
export function listSandboxPolicies(sandboxName: string) {
const builtin = policies.listPresets();
...
allPresets.forEach((p) => {
...
console.log(` ${marker} ${p.name} — ${p.description}${suffix}`);
});
}
The renderer just prints p.description verbatim. Since p.description contains the whole YAML body for whatsapp, the user sees it on screen.
Suggested fix (do both):
a. Quote whatsapp.yaml's description line to match the other 18 presets:
description: "WhatsApp Web WebSocket and media access"
This is a 1-character change in the blueprint and is the simplest immediate fix.
b. Harden the regex in src/lib/policy/index.ts so a future unquoted description can never recur:
- replace
[^"]* with [^\n]* to keep the capture line-scoped, OR
- parse the YAML with
js-yaml / yaml and read preset.description directly (the file is already valid YAML; the regex approach is brittle and has just one such bug-class hit).
Either fix individually resolves the symptom; doing both gives a data fix AND a structural fix so this can't repeat for new presets.
Logs
Not captured (CLI surface — no runtime logs involved).
NVB#6229512
Description
nemoclaw <name> policy-listalways renders the entire YAML body of thewhatsapppreset (network_policies, endpoints, comments, the lot) as if it were that preset's description. Every other preset renders cleanly because theirdescription:lines are double-quoted, which stops the parser's regex at the closing quote.whatsapp.yamlis the only preset whosedescription:is unquoted, so the regex greedily captures fromdescription:all the way to end-of-file. Result: the policy-list output ends with a confusing dump of WhatsApp's full preset definition (host: web.whatsapp.com,tls: skip, Noise-over-WebSocket comments, etc.), regardless of whetherwhatsappis applied to the sandbox.Two-sided fix: (a) the regex in
src/lib/policy/index.tsis fragile and should use a proper YAML parser or at least[^\n]*so unquoted descriptions can't run past end-of-line; (b) quotewhatsapp.yaml's description to match the convention used by the other 18 presets.Environment
Steps to Reproduce
network_policies:block with the whatsapp preset's YAML body appears, even though whatsapp is NOT applied (its bullet shows ○).Expected Result
The output ends with the last preset's
○ whatsapp — <description>bullet line. No raw YAML body appears unless a future feature explicitly renders it. (For comparison, every other preset's bullet line is one tidy entry — the whatsapp one is the only one that spills.)Actual Result
Code Analysis
1) The parser at
src/lib/policy/index.ts:53-71uses regex on raw YAML:Problem with regex (A):
[^"]*is greedy AND matches newlines (negated character classes include\nby default in JavaScript regex). Combined with the/mflag, the regex looks line-anchored but the[^"]*capture group happily spans newlines until it hits a"or EOF. Every preset description is quoted (description: "..."), so capture stops at the closing quote. EXCEPT whatsapp:nemoclaw-blueprint/policies/presets/whatsapp.yaml(line 5):With no quotes on the description line, the regex's
[^"]*group greedily slurps from "WhatsApp Web..." all the way to the next"in the file — which is thetls: skipblock'shost: "*.web.whatsapp.com"double quote, several screenfuls down. That captured chunk becomes the "description" rendered to the user.2) Quoting consistency verified across all 19 preset YAMLs:
(Generated with a one-shot grep across
nemoclaw-blueprint/policies/presets/*.yaml.)3) Renderer at
src/lib/actions/sandbox/policy-channel.ts:231-270:The renderer just prints
p.descriptionverbatim. Sincep.descriptioncontains the whole YAML body for whatsapp, the user sees it on screen.Suggested fix (do both):
a. Quote
whatsapp.yaml's description line to match the other 18 presets:This is a 1-character change in the blueprint and is the simplest immediate fix.
b. Harden the regex in
src/lib/policy/index.tsso a future unquoted description can never recur:[^"]*with[^\n]*to keep the capture line-scoped, ORjs-yaml/yamland readpreset.descriptiondirectly (the file is already valid YAML; the regex approach is brittle and has just one such bug-class hit).Either fix individually resolves the symptom; doing both gives a data fix AND a structural fix so this can't repeat for new presets.
Logs
Not captured (CLI surface — no runtime logs involved).
NVB#6229512