Skip to content

[Ubuntu 24.04][CLI&UX] policy-list output appends spurious whatsapp YAML body to last preset's description (regex parser greedy-captures unquoted description) #4312

@hulynn

Description

@hulynn

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

  1. Have any healthy sandbox with any policy presets applied.
  2. Run:
    nemoclaw <name> policy-list
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    NV QABugs found by the NVIDIA QA Teamarea: cliCommand line interface, flags, terminal UX, or outputarea: policyNetwork policy, egress rules, presets, or sandbox policyintegration: whatsappWhatsApp integration or channel behaviorplatform: ubuntuAffects Ubuntu Linux environmentsv0.0.59Release target
    No fields configured for Enhancement.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions