Skip to content

feat(messaging): onboard Mattermost for OpenClaw - #5592

Closed
sandl99 wants to merge 13 commits into
mainfrom
feat/onboard-mattermost-openclaw
Closed

feat(messaging): onboard Mattermost for OpenClaw#5592
sandl99 wants to merge 13 commits into
mainfrom
feat/onboard-mattermost-openclaw

Conversation

@sandl99

@sandl99 sandl99 commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Onboards Mattermost as an OpenClaw messaging channel using the manifest-first messaging pipeline. The integration supports self-hosted HTTP/HTTPS Mattermost URLs, generated network policy templates, bot token reachability checks, and OpenClaw config rendering without enabling Hermes support yet.
DON'T add docs in this PR yet.

Key features:

  1. Onboard Mattermost for OpenClaw
  2. Self-hosted support + networking policy

Result

image

Related Issue

Part of #5492

Changes

  • Added the Mattermost channel manifest, template resolver, reachability hook, and OpenClaw channel registration.
  • Added generated self-hosted Mattermost policy template rendering with private-network support and REST/WebSocket API rules.
  • Wired generated policy templates through onboard, rebuild, host-state persistence, setup application, and channels add policy application.
  • Added focused tests for manifest compilation, URL policy rendering, reachability validation, generated policy application order, and OpenClaw config shape.
  • Ratcheted the legacy channels-add-preset test-file budget after splitting generated-policy coverage into a focused test file.

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

  • PR description includes the DCO sign-off declaration and every commit appears as Verified in GitHub
  • Git hooks passed during commit and push, or npx prek run --from-ref main --to-ref HEAD passes
  • Targeted tests pass for changed behavior
  • Full npm test passes (broad runtime changes only)
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • 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: San Dang sdang@nvidia.com

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added Mattermost as a supported messaging platform, including bot-token authentication, base URL enrollment, and allowlist/require-mention controls.
    • Introduced generated messaging policy templates so channel enablement/enrollment can apply per-channel network policy content (including Mattermost).
  • Tests

    • Expanded end-to-end and unit coverage for Mattermost: manifest wiring, template resolution/rendering, reachability checks with safer URL validation and skip option, and onboarding/enrollment policy application behavior.
    • Updated related test expectations (including budgets and merged plan template handling).

@sandl99 sandl99 self-assigned this Jun 22, 2026
@github-code-quality

github-code-quality Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in the feat/onboard-matterm... branch is 96%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main feat/onboard-matterm... 2da5ab8 +/-
nemoclaw/src/se...cret-scanner.ts 100%
nemoclaw/src/commands/slash.ts 100%
nemoclaw/src/li...bprocess-env.ts 100%
nemoclaw/src/bl...eprint/state.ts 98%
nemoclaw/src/onboard/config.ts 98%
nemoclaw/src/bl...int/snapshot.ts 97%
nemoclaw/src/bl...print/runner.ts 95%
nemoclaw/src/co...ration-state.ts 94%
nemoclaw/src/bl...ate-networks.ts 94%
nemoclaw/src/index.ts 94%

TypeScript / code-coverage/cli

The overall coverage in the feat/onboard-matterm... branch is 46%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main feat/onboard-matterm... 2da5ab8 +/-
src/lib/state/o...oard-session.ts 91%
src/lib/inference/local.ts 76%
src/lib/sandbox/config.ts 72%
src/lib/actions...dbox/rebuild.ts 67%
src/lib/onboard/preflight.ts 64%
src/lib/actions...licy-channel.ts 56%
src/lib/state/sandbox.ts 55%
src/lib/policy/index.ts 49%
src/lib/onboard...er-gpu-patch.ts 44%
src/lib/onboard.ts 18%

Updated June 24, 2026 07:55 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@coderabbitai

coderabbitai Bot commented Jun 22, 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

Adds Mattermost as a built-in NemoClaw messaging channel using a new generated policy template mechanism. The change introduces a ChannelPolicyTemplateSpec type, a policy template renderer engine, a Mattermost channel manifest with token-based auth, a reachability hook, a template resolver, and wires all components through the compiler, applier, and onboard policy-selection flows.

Changes

Mattermost Channel Onboarding

Layer / File(s) Summary
Manifest and plan type contracts
src/lib/messaging/manifest/types.ts, src/lib/messaging/applier/types.ts
ChannelManifest gains policyTemplates?: readonly ChannelPolicyTemplateSpec[]; SandboxMessagingNetworkPolicyPlan gains an optional templates array; MessagingPolicyApplyOptions adds applyPresetContent callback; MessagingPolicyApplyResult adds appliedTemplatePresets.
Policy template renderer engine
nemoclaw-blueprint/policies/templates/mattermost.yaml, src/lib/messaging/compiler/engines/policy-template-renderer.ts, src/lib/messaging/compiler/engines/policy-template-renderer.test.ts
New renderPolicyTemplate and renderTemplateUrlContext functions load, token-substitute, and parse YAML policy templates; validate URLs, reject unsafe inputs, inject agent binaries, normalize ports; Mattermost blueprint YAML template defines the network_policies.mattermost endpoint rule set with REST and WebSocket paths.
Mattermost channel manifest, template resolver, and reachability hook
src/lib/messaging/channels/mattermost/manifest.ts, src/lib/messaging/channels/mattermost/template-resolver.ts, src/lib/messaging/channels/mattermost/hooks/reachability.ts, src/lib/messaging/channels/mattermost/hooks/index.ts
mattermostManifest defines token auth, enrollment inputs, credential/provider wiring, a mattermost.yaml policy template reference, render fragments, persisted state, and enroll hooks. resolveMattermostTemplateReference computes base URL normalization, group policy, and allowlist outputs. The reachability hook performs an authenticated GET /api/v4/users/me call with timeout, 401/403 error handling, and an env-based skip flag.
Register Mattermost in built-in registries
src/lib/messaging/channels/built-ins.ts, src/lib/messaging/channels/template-resolver.ts, src/lib/messaging/hooks/builtins.ts, src/lib/messaging/channels/metadata.ts, agents/openclaw/manifest.yaml
mattermostManifest inserted into BUILT_IN_CHANNEL_MANIFESTS; resolveMattermostTemplateReference added to BUILT_IN_TEMPLATE_REFERENCE_RESOLVERS; createMattermostHookRegistrations wired into createBuiltInMessagingHookRegistrations; mattermost added to openclaw agent supported messaging platforms.
Compiler: render policy templates during plan compilation
src/lib/messaging/compiler/engines/policy-resolver.ts, src/lib/messaging/compiler/manifest-compiler.ts, src/lib/messaging/compiler/workflow-planner.ts
planNetworkPolicy gains an optional inputRegistry parameter and renders policyTemplates per manifest via renderPolicyTemplate; ManifestCompiler.compile passes inputRegistry into planNetworkPolicy; mergeSandboxMessagingPlans and removePlanChannel merge/filter networkPolicy.templates by channel.
Policy applier: apply generated template presets at OpenShell
src/lib/messaging/applier/policy.ts, src/lib/messaging/applier/host-state-applier.ts
applyPolicyAtOpenShell derives activeTemplates, aggregates policyKeys from both entries and templates, applies each template via applyPresetContent, and reports appliedTemplatePresets; mergeSandboxMessagingPlans merges networkPolicy.templates.
Onboard: generated policy templates module and policy-selection integration
src/lib/onboard/messaging-policy-templates.ts, src/lib/onboard/policy-selection.ts
New applyGeneratedMessagingPolicyTemplates and applyGeneratedMessagingPolicyTemplatesFromRegistry helpers; setupPoliciesWithSelectionInner calls the registry helper after preset sync on all three paths (resume, non-interactive, interactive).
Channel enable/remove: applyChannelPolicyIfAvailable
src/lib/actions/sandbox/policy-channel.ts
addSandboxChannel derives preset names from manifest.policyPresets and validates each; new applyChannelPolicyIfAvailable first attempts generated templates then falls back to applyChannelPresetIfAvailable; both QR and non-QR enable paths switch to the new function; removeChannelPresetIfPresent checks getAppliedPresets instead of built-in-presets membership.
Diagnostics and persistence updates
src/lib/messaging/diagnostics.ts, src/lib/messaging/persistence.ts
collectMessagingChannelDiagnostics uses a new policyNames(presets, templates) helper to include template names in policyPresets; hydrateDerivedSandboxMessagingPlanFields preserves persisted networkPolicy when templates are present.
Tests: manifest, hooks, resolver, channel metadata
src/lib/messaging/channels/manifests.test.ts, src/lib/messaging/channels/mattermost/hooks/reachability.test.ts, src/lib/messaging/channels/mattermost/template-resolver.test.ts, src/lib/messaging/channels/metadata.test.ts, src/lib/messaging/hooks/hook-runner.test.ts, src/lib/messaging-channel-config.test.ts, src/lib/agent/defs.test.ts
Full coverage of Mattermost manifest wiring, reachability hook scenarios (success/401/unreachable/skip-env), template resolver URL normalization and group policy derivation, metadata assertions across credential/provider/policy/runtime queries, and hook registry listIds() update.
Tests: compiler, applier, integration
src/lib/messaging/applier/setup-applier.test.ts, src/lib/messaging/compiler/manifest-compiler.test.ts, test/channels-add-generated-policy.test.ts, test/channels-add-preset.test.ts, src/lib/sandbox/channels.test.ts, test/sandbox-provider-cleanup.test.ts, src/lib/messaging/diagnostics.test.ts, src/lib/onboard/messaging-prep.test.ts, test/policy-tiers-onboard.test.ts, ci/test-file-size-budget.json
Applier test asserts applyPresetContent invocation and appliedTemplatePresets; compiler test validates Mattermost credential bindings, networkPolicy.templates YAML, and Hermes exclusion; new integration test asserts generated-policy apply ordering and source-of-truth channel coverage; remaining test files add Mattermost to all relevant assertion sets.

Sequence Diagrams

sequenceDiagram
  participant CLI
  participant addSandboxChannel
  participant applyChannelPolicyIfAvailable
  participant applyGeneratedMessagingPolicyTemplates
  participant policies as policies (applyPresetContent)
  participant applyChannelPresetIfAvailable

  CLI->>addSandboxChannel: channel="mattermost"
  addSandboxChannel->>addSandboxChannel: derive preset names from manifest.policyPresets
  addSandboxChannel->>applyChannelPolicyIfAvailable: sandboxName, channelName, plan
  applyChannelPolicyIfAvailable->>applyGeneratedMessagingPolicyTemplates: sandboxName, plan, channelId
  applyGeneratedMessagingPolicyTemplates->>policies: applyPresetContent("mattermost", content, options)
  policies-->>applyGeneratedMessagingPolicyTemplates: true
  applyGeneratedMessagingPolicyTemplates-->>applyChannelPolicyIfAvailable: ["mattermost"]
  applyChannelPolicyIfAvailable->>applyChannelPolicyIfAvailable: refresh policy context
  applyChannelPolicyIfAvailable-->>addSandboxChannel: true (templates applied)
  addSandboxChannel-->>CLI: channel enabled
Loading
sequenceDiagram
  participant ManifestCompiler
  participant planNetworkPolicy
  participant renderPolicyTemplate
  participant renderTemplateUrlContext
  participant readPolicyTemplate as readPolicyTemplate (mattermost.yaml)

  ManifestCompiler->>planNetworkPolicy: manifests, context, inputRegistry
  planNetworkPolicy->>renderPolicyTemplate: channelId="mattermost", spec, agent, inputs
  renderPolicyTemplate->>renderTemplateUrlContext: baseUrl value, "http-url"
  renderTemplateUrlContext-->>renderPolicyTemplate: host/port/basePath
  renderPolicyTemplate->>readPolicyTemplate: "mattermost.yaml"
  readPolicyTemplate-->>renderPolicyTemplate: raw YAML
  renderPolicyTemplate->>renderPolicyTemplate: substitute tokens, inject binaries, parse YAML
  renderPolicyTemplate-->>planNetworkPolicy: SandboxMessagingNetworkPolicyTemplatePlan
  planNetworkPolicy-->>ManifestCompiler: plan with templates: [mattermost]
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

  • NVIDIA/NemoClaw#5492: Tracks comprehensive Mattermost messaging channel support, which this PR directly implements with manifest, policy templates, hooks, template resolvers, and integration tests.

Suggested labels

documentation, v0.0.66

Poem

🐇 A new bridge is built, hop hop hop!
Mattermost joins the channel crop.
Token pasted, URL set,
The policy YAML renders yet.
WebSocket and REST in hand,
The rabbit helps the teams expand! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.86% 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
Title check ✅ Passed The title 'feat(messaging): onboard Mattermost for OpenClaw' clearly summarizes the main change—adding Mattermost support to the OpenClaw messaging system—which aligns perfectly with the comprehensive changeset.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/onboard-mattermost-openclaw

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

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: messaging-providers-vitest, channels-add-remove-vitest, network-policy-vitest, cloud-onboard-vitest, cloud-inference-vitest, cron-preflight-inference-local-vitest
Optional E2E: issue-4434-tui-unreachable-inference-vitest, channels-stop-start-vitest, messaging-compatible-endpoint-vitest

Dispatch hint: messaging-providers-vitest,channels-add-remove-vitest,network-policy-vitest,cloud-onboard-vitest,cloud-inference-vitest,cron-preflight-inference-local-vitest

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • messaging-providers-vitest (high): Validates the real messaging provider/placeholder/L7-proxy chain, channel config rendering, credential isolation, and policy behavior for token-backed and QR-only channels. This is the closest existing E2E for the Mattermost channel plumbing and generated policy application changes.
  • channels-add-remove-vitest (high): Exercises the real channels add/rebuild/channels remove lifecycle, including applying channel-owned policies and keeping registry/session/policy state aligned. Required because src/lib/actions/sandbox/policy-channel.ts now chooses generated policy templates before channel-named presets.
  • network-policy-vitest (high): Runs live OpenShell sandbox network-policy allow/deny probes. Required because this PR changes policy template rendering/application and adds REST/WebSocket credential-rewrite policy content for Mattermost.
  • cloud-onboard-vitest (high): Covers full hosted install/onboard through the real CLI and sandbox path. Required because onboarding messaging policy selection/prep and supported channel metadata changed and can affect end-to-end hosted onboarding.
  • cloud-inference-vitest (high): Validates a real sandbox can reach hosted inference through inference.local after install/onboard. Required because the Dockerfile changes OpenClaw fetch-guard proxy defaults used inside OpenShell sandboxes.
  • cron-preflight-inference-local-vitest (medium): Specifically guards the cron model-provider preflight/inference.local path that previously required a Dockerfile patch and is now intended to be covered by the broader bare guarded-fetch proxy default.

Optional E2E

  • issue-4434-tui-unreachable-inference-vitest (high): Additional confidence for OpenClaw TUI/agent access to inference.local under the changed Dockerfile fetch-guard proxy behavior.
  • channels-stop-start-vitest (high): Useful adjacent coverage for channel registry, provider reuse, policy-list, and rebuild/start behavior after adding a new supported channel and generated policy templates. Not merge-blocking because the changed channel-add path is more directly covered by channels-add-remove.
  • messaging-compatible-endpoint-vitest (medium): Adjacent confidence for messaging plus inference.local through a hermetic OpenAI-compatible endpoint, especially because Dockerfile proxy defaults and messaging config paths changed together.

New E2E recommendations

  • Mattermost messaging channel (high): Existing messaging/channel E2Es cover Telegram/Discord/Slack/WhatsApp-style paths but do not appear to exercise Mattermost-specific generated policy templates, self-hosted base URLs, REST plus WebSocket policy rules, Mattermost reachability, or MATTERMOST_BOT_TOKEN placeholder rewriting in a live sandbox.
    • Suggested test: Add a mattermost-channel-e2e using a hermetic fake Mattermost REST/WebSocket server to run onboard or channels add mattermost, verify generated policy content from MATTERMOST_URL, provider placeholder redaction, L7 token rewrite, WebSocket allow rule, rebuild persistence, and channels remove cleanup.
  • OpenClaw bare guarded-fetch proxy default (medium): Cron and inference tests cover important callsites, but the Dockerfile patch changes the global default for bare fetchWithSsrFGuard calls inside OpenShell sandboxes. A focused E2E would reduce reliance on indirect coverage when upstream OpenClaw dist shapes change.
    • Suggested test: Add a bare-guarded-fetch-proxy-e2e that runs a minimal OpenClaw/plugin or sandbox-side probe with an omitted guarded-fetch mode against an endpoint only reachable through the OpenShell L7 proxy, and asserts both success for allowed hosts and denial for disallowed/private targets.

Dispatch hint

  • Workflow: e2e-vitest-scenarios.yaml
  • jobs input: messaging-providers-vitest,channels-add-remove-vitest,network-policy-vitest,cloud-onboard-vitest,cloud-inference-vitest,cron-preflight-inference-local-vitest

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Recommendation

Required Vitest E2E scenarios: cron-preflight-inference-local-vitest, network-policy-vitest, messaging-providers-vitest, channels-add-remove-vitest, onboard-resume-vitest, onboard-repair-vitest
Optional Vitest E2E scenarios: issue-4434-tui-unreachable-inference-vitest, messaging-compatible-endpoint-vitest

Dispatch required Vitest E2E scenarios:

  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=cron-preflight-inference-local-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=network-policy-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=messaging-providers-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=channels-add-remove-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=onboard-resume-vitest
  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=onboard-repair-vitest

Workflow run

Full Vitest E2E advisor summary

Vitest E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required Vitest E2E scenarios

  • cron-preflight-inference-local-vitest: Dockerfile changes replace the prior cron-specific OpenClaw fetch-guard patch with a broader sandbox trusted-env-proxy default for bare guarded fetches. This job is the focused live Vitest coverage for inference.local cron preflight behavior in the sandbox.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=cron-preflight-inference-local-vitest
  • network-policy-vitest: The PR changes OpenClaw SSRF/proxy patching and adds generated Mattermost network policy template content. This job exercises live policy mutation/enforcement, SSRF private-address rejection, and web_fetch host-gateway allow/deny behavior through the real sandbox boundary.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=network-policy-vitest
  • messaging-providers-vitest: The PR changes built-in messaging channel registration, manifest compilation/planning, credential/policy application, persistence, diagnostics, and OpenClaw agent manifest messaging support. This job exercises live messaging provider placeholders, policies, runtime config, and secret-boundary contracts.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=messaging-providers-vitest
  • channels-add-remove-vitest: The PR changes channels add/remove policy application to support generated messaging policy templates while preserving preset fallback behavior. This job exercises the real channel add, rebuild, policy-list, registry/gateway state, and remove cleanup path.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=channels-add-remove-vitest
  • onboard-resume-vitest: Onboarding policy-selection and generated messaging policy-template changes touch resume-time policy reapplication from saved session/registry state. The onboarding resume compatibility rule requires this job.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=onboard-resume-vitest
  • onboard-repair-vitest: The same onboarding policy-selection and generated-template changes can affect repair/backstop execution from persisted sessions, so repair is required alongside resume for these state-machine paths.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=onboard-repair-vitest

Optional Vitest E2E scenarios

  • issue-4434-tui-unreachable-inference-vitest: Adjacent coverage for the broader Dockerfile fetch-guard default change: this exercises a live OpenClaw TUI/unreachable-inference path that can also depend on sandbox proxy routing for guarded fetches.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=issue-4434-tui-unreachable-inference-vitest
  • messaging-compatible-endpoint-vitest: Adjacent messaging coverage for endpoint compatibility and proxy/header behavior; useful because the PR changes messaging manifests/policy planning, but it is not the primary Mattermost/channel add surface.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=messaging-compatible-endpoint-vitest

Relevant changed files

  • Dockerfile
  • agents/openclaw/manifest.yaml
  • nemoclaw-blueprint/policies/templates/mattermost.yaml
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/messaging/applier/host-state-applier.ts
  • src/lib/messaging/applier/policy.ts
  • src/lib/messaging/applier/types.ts
  • src/lib/messaging/channels/built-ins.ts
  • src/lib/messaging/channels/mattermost/hooks/index.ts
  • src/lib/messaging/channels/mattermost/hooks/reachability.ts
  • src/lib/messaging/channels/mattermost/manifest.ts
  • src/lib/messaging/channels/mattermost/template-resolver.ts
  • src/lib/messaging/channels/metadata.ts
  • src/lib/messaging/channels/template-resolver.ts
  • src/lib/messaging/compiler/engines/policy-resolver.ts
  • src/lib/messaging/compiler/engines/policy-template-renderer.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/messaging/diagnostics.ts
  • src/lib/messaging/hooks/builtins.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/messaging/persistence.ts
  • src/lib/onboard/messaging-policy-templates.ts
  • src/lib/onboard/policy-selection.ts

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Blocked

Merge posture: Do not merge until addressed
Primary next action: Fix PRA-5: Mattermost URL input can still generate private/internal sandbox egress; then add or justify PRA-T1.
Open items: 4 required · 7 warnings · 0 suggestions · 8 test follow-ups
Since last review: 2 prior items resolved · 7 still apply · 1 new item found

Action checklist

  • PRA-5 Fix: Mattermost URL input can still generate private/internal sandbox egress in src/lib/messaging/compiler/engines/policy-template-renderer.ts:96
  • PRA-6 Fix: Mattermost bearer tokens are allowed over cleartext HTTP in src/lib/messaging/channels/mattermost/manifest.ts:32
  • PRA-7 Fix: Missing Mattermost policy-template source can silently drop generated policy in src/lib/messaging/compiler/engines/policy-template-renderer.ts:49
  • PRA-8 Fix: Mattermost user-facing setup and policy behavior are undocumented in docs/manage-sandboxes/messaging-channels.mdx:1
  • PRA-1 Resolve or justify: Source-of-truth review needed: Mattermost URL-to-policy generation
  • PRA-2 Resolve or justify: Source-of-truth review needed: Generated messaging policy template lifecycle
  • PRA-3 Resolve or justify: Source-of-truth review needed: Missing Mattermost policy-template source input
  • PRA-4 Resolve or justify: Source-of-truth review needed: Mattermost reachability response logging
  • PRA-9 Resolve or justify: Mattermost reachability logs untrusted response bodies at a credential boundary in src/lib/messaging/channels/mattermost/hooks/reachability.ts:69
  • PRA-10 Resolve or justify: Generated Mattermost policy lifecycle is not proven end-to-end in src/lib/messaging/compiler/workflow-planner.ts:83
  • PRA-11 Resolve or justify: Mattermost assertions grow shared messaging test monoliths despite focused test files in src/lib/messaging/channels/manifests.test.ts:585
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Runtime validation
  • PRA-T6 Add or justify test follow-up: Acceptance clause
  • PRA-T7 Add or justify test follow-up: Acceptance clause
  • PRA-T8 Add or justify test follow-up: Acceptance clause

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-4 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-5 Required security src/lib/messaging/compiler/engines/policy-template-renderer.ts:96 Add one shared Mattermost URL security validator used by both `renderTemplateUrlContext()` and `normalizeMattermostBaseUrl()`. Reject localhost, loopback, link-local, cloud metadata, RFC1918/private IP literals, reserved IPs, wildcard or ambiguous hosts, and internal-only DNS suffixes by default. If private Mattermost deployments are intentionally supported, require an explicit reviewed opt-in with narrow host/IP validation and operator-visible policy text.
PRA-6 Required security src/lib/messaging/channels/mattermost/manifest.ts:32 Require HTTPS by default before reachability validation or generated policy content is produced. If HTTP is required for a local lab/private deployment, gate it behind the same explicit private-host opt-in and prove that bearer tokens are never sent to arbitrary cleartext endpoints by default.
PRA-7 Required correctness src/lib/messaging/compiler/engines/policy-template-renderer.ts:49 Make required policy-template sources impossible to miss: either fail plan compilation with a clear diagnostic, or mark the channel inactive/skipped with an operator-visible reason before credentials, providers, registry state, or policy state are mutated. Document whether rendered template content or persisted `mattermostConfig.baseUrl` is the rebuild source of truth.
PRA-8 Required docs docs/manage-sandboxes/messaging-channels.mdx:1 Update the messaging channel documentation for Mattermost setup, OpenClaw-only scope, bot token creation, URL/security requirements, generated policy lifecycle, allowed users/channels, mention mode, troubleshooting, and any explicit opt-in behavior for private or HTTP deployments.
PRA-9 Resolve/justify security src/lib/messaging/channels/mattermost/hooks/reachability.ts:69 Log only HTTP status and a coarse failure reason by default. If body details are needed, gate them behind an explicit verbose/debug mode and redact Authorization values, bearer tokens, and common secret patterns before logging.
PRA-10 Resolve/justify correctness src/lib/messaging/compiler/workflow-planner.ts:83 Add Mattermost-specific lifecycle coverage and fix any exposed gaps: `channels remove mattermost` should remove the generated custom policy and prune `networkPolicy.templates`; stop should prevent generated policy application while preserving reusable provider state; start and rebuild/resume should reapply generated policy from the documented source of truth.
PRA-11 Resolve/justify architecture src/lib/messaging/channels/manifests.test.ts:585 Move most Mattermost-specific manifest and compiler shape assertions into focused Mattermost test files or small local helpers. Leave shared suites for registration, serialization, agent availability, cross-channel smoke, and security invariants that must apply to every channel.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-5 Required — Mattermost URL input can still generate private/internal sandbox egress

  • Location: src/lib/messaging/compiler/engines/policy-template-renderer.ts:96
  • Category: security
  • Problem: `MATTERMOST_URL` is accepted after only syntactic URL parsing and a simple hostname regex, then rendered into `nemoclaw-blueprint/policies/templates/mattermost.yaml` as the allowed host, port, and API path. The reachability hook has a separate similarly weak normalizer, so an unsafe URL can be fetched with a bearer token and then persisted as generated policy content.
  • Impact: A mistaken or malicious Mattermost URL can widen the sandbox network policy toward loopback, cloud metadata, RFC1918/private networks, link-local services, or internal-only DNS names. That weakens NemoClaw's SSRF and sandbox egress boundary for an OpenClaw channel.
  • Required action: Add one shared Mattermost URL security validator used by both `renderTemplateUrlContext()` and `normalizeMattermostBaseUrl()`. Reject localhost, loopback, link-local, cloud metadata, RFC1918/private IP literals, reserved IPs, wildcard or ambiguous hosts, and internal-only DNS suffixes by default. If private Mattermost deployments are intentionally supported, require an explicit reviewed opt-in with narrow host/IP validation and operator-visible policy text.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read `renderTemplateUrlContext()` in `src/lib/messaging/compiler/engines/policy-template-renderer.ts` and `normalizeMattermostBaseUrl()` in `src/lib/messaging/channels/mattermost/hooks/reachability.ts`; trace the accepted host into `nemoclaw-blueprint/policies/templates/mattermost.yaml` as `{{url.host}}` and into the reachability fetch URL.
  • Missing regression test: Add table-driven tests proving both policy rendering and reachability reject `https://127.0.0.1:8065\`, `https://localhost:8065\`, `https://169.254.169.254\`, `https://10.0.0.5:8065\`, `https://192.168.1.5:8065\`, `https://0.0.0.0:8065\`, and `https://foo.internal\` before any fetch or policy content is produced.
  • Done when: The required change is committed and verification passes: Read `renderTemplateUrlContext()` in `src/lib/messaging/compiler/engines/policy-template-renderer.ts` and `normalizeMattermostBaseUrl()` in `src/lib/messaging/channels/mattermost/hooks/reachability.ts`; trace the accepted host into `nemoclaw-blueprint/policies/templates/mattermost.yaml` as `{{url.host}}` and into the reachability fetch URL.
  • Evidence: `renderTemplateUrlContext()` lowercases `url.hostname` and accepts it when it matches `/^[a-z0-9.-]+$/`; `normalizeMattermostBaseUrl()` accepts any `http:` or `https:` URL without host/IP classification; current tests assert IP-literal URL acceptance.

PRA-6 Required — Mattermost bearer tokens are allowed over cleartext HTTP

  • Location: src/lib/messaging/channels/mattermost/manifest.ts:32
  • Category: security
  • Problem: The Mattermost base URL prompt and `formatPattern` accept `http://`, the policy template declares `sourceType: "http-url"`, and the reachability hook sends `Authorization: Bearer <token>` to the normalized base URL.
  • Impact: A Mattermost bot token can be disclosed on the network when an HTTP endpoint is configured, and the generated sandbox policy then permits the agent to continue using that same cleartext endpoint.
  • Required action: Require HTTPS by default before reachability validation or generated policy content is produced. If HTTP is required for a local lab/private deployment, gate it behind the same explicit private-host opt-in and prove that bearer tokens are never sent to arbitrary cleartext endpoints by default.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Inspect `mattermostManifest.inputs.baseUrl.formatPattern`, `policyTemplates[0].sourceType`, and `fetchWithTimeout()` in the reachability hook; the current tests in `manifests.test.ts` and `policy-template-renderer.test.ts` also show HTTP acceptance.
  • Missing regression test: Add tests that `http://chat.example.com\` and `http://192.168.1.5:8065\` are rejected before `fetch` is called and before `renderPolicyTemplate()` returns policy content, unless an explicit reviewed opt-in is implemented.
  • Done when: The required change is committed and verification passes: Inspect `mattermostManifest.inputs.baseUrl.formatPattern`, `policyTemplates[0].sourceType`, and `fetchWithTimeout()` in the reachability hook; the current tests in `manifests.test.ts` and `policy-template-renderer.test.ts` also show HTTP acceptance.
  • Evidence: `formatPattern: "^https?://..."` and prompt help mention `http://host:port\`; `normalizeMattermostBaseUrl()` allows `http:`; `fetchWithTimeout()` always sets the bearer `Authorization` header.

PRA-7 Required — Missing Mattermost policy-template source can silently drop generated policy

  • Location: src/lib/messaging/compiler/engines/policy-template-renderer.ts:49
  • Category: correctness
  • Problem: `renderPolicyTemplate()` returns `null` when the configured `sourceInput` has no non-empty string value. The caller filters nulls out, so the plan can omit generated policy content without a targeted diagnostic from the policy-template layer.
  • Impact: If rebuild hydration, persisted state, or a future manifest change leaves Mattermost active without a renderable `baseUrl`, credentials and OpenClaw config can be planned while the required egress policy is absent or stale. Operators get a channel setup that appears enabled but cannot safely or predictably reach the intended Mattermost server.
  • Required action: Make required policy-template sources impossible to miss: either fail plan compilation with a clear diagnostic, or mark the channel inactive/skipped with an operator-visible reason before credentials, providers, registry state, or policy state are mutated. Document whether rendered template content or persisted `mattermostConfig.baseUrl` is the rebuild source of truth.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read `renderPolicyTemplate()` and `planNetworkPolicy()` together; confirm that `null` templates are dropped and that no Mattermost-specific diagnostic is emitted for a missing template source.
  • Missing regression test: Add a compiler test where Mattermost has a bot token but no `MATTERMOST_URL`, and assert either a clear compile error or an inactive/skipped channel with no credential binding, no agent render, and no generated policy side effects.
  • Done when: The required change is committed and verification passes: Read `renderPolicyTemplate()` and `planNetworkPolicy()` together; confirm that `null` templates are dropped and that no Mattermost-specific diagnostic is emitted for a missing template source.
  • Evidence: `const sourceValue = inputStringValue(...); if (!sourceValue) return null;` is followed by `flatMap(... return rendered ? [rendered] : [])` in `planNetworkPolicy()`.

PRA-8 Required — Mattermost user-facing setup and policy behavior are undocumented

  • Location: docs/manage-sandboxes/messaging-channels.mdx:1
  • Category: docs
  • Problem: This PR adds a user-facing channel, bot-token enrollment, base URL rules, generated custom policy content, allowlist controls, and troubleshooting-relevant reachability behavior, but the messaging channel docs contain no Mattermost section.
  • Impact: Operators cannot tell which URLs are accepted, whether HTTP/private hosts are safe, how generated policy is applied or removed, what IDs to provide, or how to troubleshoot reachability failures. That is especially risky for a feature that changes sandbox egress policy and handles bot credentials.
  • Required action: Update the messaging channel documentation for Mattermost setup, OpenClaw-only scope, bot token creation, URL/security requirements, generated policy lifecycle, allowed users/channels, mention mode, troubleshooting, and any explicit opt-in behavior for private or HTTP deployments.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Search `docs/manage-sandboxes/messaging-channels.mdx` and the rest of `docs/` for `Mattermost`; the current checkout has no Mattermost documentation.
  • Missing regression test: If docs lint/frontmatter checks exist for changed docs, include the Mattermost section in that validation; otherwise the evidence is the added doc section itself plus a docs build in the normal docs workflow.
  • Done when: The required change is committed and verification passes: Search `docs/manage-sandboxes/messaging-channels.mdx` and the rest of `docs/` for `Mattermost`; the current checkout has no Mattermost documentation.
  • Evidence: The PR body marks `Docs updated for user-facing behavior changes` unchecked, and a read-only grep found no `mattermost` matches under `docs/`.
Review findings by urgency: 4 required fixes, 7 items to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: Mattermost URL-to-policy generation

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by the required missing test in the URL-validation security finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Two separate URL normalizers accept HTTP/HTTPS without host/IP classification.

PRA-2 Resolve/justify — Source-of-truth review needed: Generated messaging policy template lifecycle

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by the lifecycle test recommendations in the generated-policy lifecycle finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `applyGeneratedMessagingPolicyTemplatesFromRegistry()` reapplies plan content; remove/disable filtering exists in code but Mattermost-specific end-to-end lifecycle tests were not found.

PRA-3 Resolve/justify — Source-of-truth review needed: Missing Mattermost policy-template source input

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by the missing-template-source correctness finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `renderPolicyTemplate()` returns `null` for missing source input and the caller drops nulls.

PRA-4 Resolve/justify — Source-of-truth review needed: Mattermost reachability response logging

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by the log-redaction security finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `readResponseText()` output is interpolated into `logMattermostDisabled(...)`.

PRA-9 Resolve/justify — Mattermost reachability logs untrusted response bodies at a credential boundary

  • Location: src/lib/messaging/channels/mattermost/hooks/reachability.ts:69
  • Category: security
  • Problem: For non-401/403 failures, the hook reads up to 240 characters of the response body and includes it in operator logs. The body is controlled by the configured endpoint and is not redacted.
  • Impact: A malicious or misconfigured endpoint can reflect token-like strings, internal details, or other sensitive content into logs while NemoClaw is validating a bearer-token integration.
  • Recommended action: Log only HTTP status and a coarse failure reason by default. If body details are needed, gate them behind an explicit verbose/debug mode and redact Authorization values, bearer tokens, and common secret patterns before logging.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read the `!response.ok` branch in `createMattermostReachabilityHook()` and `readResponseText()`; confirm the detail string is appended to `logMattermostDisabled(...)` without redaction.
  • Missing regression test: Add a reachability test where the server returns a body containing `Bearer reflected-token` or `MATTERMOST_BOT_TOKEN=...`, and assert the default logs contain only status/coarse reason and no secret-like body content.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read the `!response.ok` branch in `createMattermostReachabilityHook()` and `readResponseText()`; confirm the detail string is appended to `logMattermostDisabled(...)` without redaction.
  • Evidence: `const detail = await readResponseText(response)` is interpolated into the log message; `readResponseText()` only normalizes whitespace and truncates.

PRA-10 Resolve/justify — Generated Mattermost policy lifecycle is not proven end-to-end

  • Location: src/lib/messaging/compiler/workflow-planner.ts:83
  • Category: correctness
  • Problem: The PR adds generated custom policy content, host-state merge support, add-time application, and remove-plan pruning, but the tests do not fully prove the operator lifecycle for generated policies: remove should remove the custom policy, stop should suppress application, start/rebuild should reapply from the documented source, and URL changes should not leave stale policy content.
  • Impact: Generated Mattermost policy can become orphaned, missing, or stale relative to the channel state. That can leave unnecessary sandbox egress open after removal/stop, or leave Mattermost enabled without the egress it needs after rebuild or URL changes.
  • Recommended action: Add Mattermost-specific lifecycle coverage and fix any exposed gaps: `channels remove mattermost` should remove the generated custom policy and prune `networkPolicy.templates`; stop should prevent generated policy application while preserving reusable provider state; start and rebuild/resume should reapply generated policy from the documented source of truth.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `removePlanChannel()`, `setPlanChannelDisabled()`, `filterEnabledPlanEntries()`, `removeChannelPresetIfPresent()`, and `applyGeneratedMessagingPolicyTemplatesFromRegistry()` together; then compare with tests, which currently cover add/onboard application but not the full Mattermost custom-policy lifecycle.
  • Missing regression test: Add tests named for the lifecycle behaviors: `channels remove mattermost removes generated custom policy and prunes networkPolicy.templates`, `channels stop mattermost does not apply generated template content`, `channels start mattermost reapplies generated template content`, and `rebuild reapplies Mattermost generated policy from the documented source of truth`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `removePlanChannel()`, `setPlanChannelDisabled()`, `filterEnabledPlanEntries()`, `removeChannelPresetIfPresent()`, and `applyGeneratedMessagingPolicyTemplatesFromRegistry()` together; then compare with tests, which currently cover add/onboard application but not the full Mattermost custom-policy lifecycle.
  • Evidence: Code now filters templates on remove and filters disabled entries at apply time, but searched tests only showed generated policy add/onboard application and generic Slack preset removal/session sync.

PRA-11 Resolve/justify — Mattermost assertions grow shared messaging test monoliths despite focused test files

  • Location: src/lib/messaging/channels/manifests.test.ts:585
  • Category: architecture
  • Problem: The PR adds focused Mattermost test files, but also grows shared manifest/compiler/setup monoliths substantially with Mattermost-specific shape assertions.
  • Impact: Shared test hotspots become harder to review and maintain, and future channel PRs already overlap these same files. This increases merge drift and makes channel-specific behavior harder to reason about.
  • Recommended action: Move most Mattermost-specific manifest and compiler shape assertions into focused Mattermost test files or small local helpers. Leave shared suites for registration, serialization, agent availability, cross-channel smoke, and security invariants that must apply to every channel.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Compare the large Mattermost block in `src/lib/messaging/channels/manifests.test.ts` and Mattermost additions in `manifest-compiler.test.ts` with the focused files under `src/lib/messaging/channels/mattermost/`.
  • Missing regression test: Existing focused Mattermost tests already cover template resolver and reachability; preserve that coverage while moving manifest/compiler shape assertions into similarly focused Mattermost test files.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Compare the large Mattermost block in `src/lib/messaging/channels/manifests.test.ts` and Mattermost additions in `manifest-compiler.test.ts` with the focused files under `src/lib/messaging/channels/mattermost/`.
  • Evidence: Synthetic drift reports `manifests.test.ts` +129 lines, `manifest-compiler.test.ts` +100 lines, and `setup-applier.test.ts` +44 lines; several open messaging channel PRs overlap these shared suites.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Simplification opportunities: 1 possible cut

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-11 shrink (src/lib/messaging/channels/manifests.test.ts:585): Mattermost-specific assertions embedded in shared manifest/compiler monolith tests.
    • Replacement: Focused Mattermost manifest/compiler tests plus minimal shared registration/serialization assertions.
    • Safety boundary: Do not remove cross-channel invariants, security negative tests, or generated-policy lifecycle coverage.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — Mattermost reachability and policy rendering reject loopback, localhost, metadata, RFC1918, link-local, 0.0.0.0, and .internal hosts before fetch or policy apply. The PR changes sandbox egress policy generation, credential-bearing reachability fetches, Dockerfile OpenClaw fetch-guard patching, and channel lifecycle policy application. Static tests are broad, but runtime/sandbox behavior and negative security paths need targeted validation.
  • PRA-T2 Runtime validation — Mattermost reachability and policy rendering reject HTTP by default before Authorization is sent or generated policy content is produced. The PR changes sandbox egress policy generation, credential-bearing reachability fetches, Dockerfile OpenClaw fetch-guard patching, and channel lifecycle policy application. Static tests are broad, but runtime/sandbox behavior and negative security paths need targeted validation.
  • PRA-T3 Runtime validation — Mattermost reachability logs only status/coarse reason and omits or redacts response body secrets. The PR changes sandbox egress policy generation, credential-bearing reachability fetches, Dockerfile OpenClaw fetch-guard patching, and channel lifecycle policy application. Static tests are broad, but runtime/sandbox behavior and negative security paths need targeted validation.
  • PRA-T4 Runtime validation — Active Mattermost channel cannot compile or apply without a rendered policy template when baseUrl is absent or invalid. The PR changes sandbox egress policy generation, credential-bearing reachability fetches, Dockerfile OpenClaw fetch-guard patching, and channel lifecycle policy application. Static tests are broad, but runtime/sandbox behavior and negative security paths need targeted validation.
  • PRA-T5 Runtime validation — channels remove mattermost removes the generated custom policy and prunes networkPolicy.templates. The PR changes sandbox egress policy generation, credential-bearing reachability fetches, Dockerfile OpenClaw fetch-guard patching, and channel lifecycle policy application. Static tests are broad, but runtime/sandbox behavior and negative security paths need targeted validation.
  • PRA-T6 Acceptance clause — The integration supports self-hosted HTTP/HTTPS Mattermost URLs, generated network policy templates, bot token reachability checks, and OpenClaw config rendering without enabling Hermes support yet. — add test evidence or identify existing coverage. Generated templates, reachability hook, and OpenClaw-only manifest are present, but HTTP/private URL support is unsafe as implemented and is covered by security blockers.
  • PRA-T7 Acceptance clause — DON'T add docs in this PR yet. — add test evidence or identify existing coverage. This is PR-provided text and not trusted as a reason to skip required user-facing docs; the changed feature needs docs and no Mattermost docs are present.
  • PRA-T8 Acceptance clause — 2. Self-hosted support + networking policy — add test evidence or identify existing coverage. `policyTemplates` and `mattermost.yaml` provide generated REST/WebSocket egress, but URL validation and lifecycle/source-of-truth coverage are incomplete.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: Mattermost URL-to-policy generation

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by the required missing test in the URL-validation security finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Two separate URL normalizers accept HTTP/HTTPS without host/IP classification.

PRA-2 Resolve/justify — Source-of-truth review needed: Generated messaging policy template lifecycle

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by the lifecycle test recommendations in the generated-policy lifecycle finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `applyGeneratedMessagingPolicyTemplatesFromRegistry()` reapplies plan content; remove/disable filtering exists in code but Mattermost-specific end-to-end lifecycle tests were not found.

PRA-3 Resolve/justify — Source-of-truth review needed: Missing Mattermost policy-template source input

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as missing.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by the missing-template-source correctness finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `renderPolicyTemplate()` returns `null` for missing source input and the caller drops nulls.

PRA-4 Resolve/justify — Source-of-truth review needed: Mattermost reachability response logging

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Covered by the log-redaction security finding.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: `readResponseText()` output is interpolated into `logMattermostDisabled(...)`.

PRA-5 Required — Mattermost URL input can still generate private/internal sandbox egress

  • Location: src/lib/messaging/compiler/engines/policy-template-renderer.ts:96
  • Category: security
  • Problem: `MATTERMOST_URL` is accepted after only syntactic URL parsing and a simple hostname regex, then rendered into `nemoclaw-blueprint/policies/templates/mattermost.yaml` as the allowed host, port, and API path. The reachability hook has a separate similarly weak normalizer, so an unsafe URL can be fetched with a bearer token and then persisted as generated policy content.
  • Impact: A mistaken or malicious Mattermost URL can widen the sandbox network policy toward loopback, cloud metadata, RFC1918/private networks, link-local services, or internal-only DNS names. That weakens NemoClaw's SSRF and sandbox egress boundary for an OpenClaw channel.
  • Required action: Add one shared Mattermost URL security validator used by both `renderTemplateUrlContext()` and `normalizeMattermostBaseUrl()`. Reject localhost, loopback, link-local, cloud metadata, RFC1918/private IP literals, reserved IPs, wildcard or ambiguous hosts, and internal-only DNS suffixes by default. If private Mattermost deployments are intentionally supported, require an explicit reviewed opt-in with narrow host/IP validation and operator-visible policy text.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read `renderTemplateUrlContext()` in `src/lib/messaging/compiler/engines/policy-template-renderer.ts` and `normalizeMattermostBaseUrl()` in `src/lib/messaging/channels/mattermost/hooks/reachability.ts`; trace the accepted host into `nemoclaw-blueprint/policies/templates/mattermost.yaml` as `{{url.host}}` and into the reachability fetch URL.
  • Missing regression test: Add table-driven tests proving both policy rendering and reachability reject `https://127.0.0.1:8065\`, `https://localhost:8065\`, `https://169.254.169.254\`, `https://10.0.0.5:8065\`, `https://192.168.1.5:8065\`, `https://0.0.0.0:8065\`, and `https://foo.internal\` before any fetch or policy content is produced.
  • Done when: The required change is committed and verification passes: Read `renderTemplateUrlContext()` in `src/lib/messaging/compiler/engines/policy-template-renderer.ts` and `normalizeMattermostBaseUrl()` in `src/lib/messaging/channels/mattermost/hooks/reachability.ts`; trace the accepted host into `nemoclaw-blueprint/policies/templates/mattermost.yaml` as `{{url.host}}` and into the reachability fetch URL.
  • Evidence: `renderTemplateUrlContext()` lowercases `url.hostname` and accepts it when it matches `/^[a-z0-9.-]+$/`; `normalizeMattermostBaseUrl()` accepts any `http:` or `https:` URL without host/IP classification; current tests assert IP-literal URL acceptance.

PRA-6 Required — Mattermost bearer tokens are allowed over cleartext HTTP

  • Location: src/lib/messaging/channels/mattermost/manifest.ts:32
  • Category: security
  • Problem: The Mattermost base URL prompt and `formatPattern` accept `http://`, the policy template declares `sourceType: "http-url"`, and the reachability hook sends `Authorization: Bearer <token>` to the normalized base URL.
  • Impact: A Mattermost bot token can be disclosed on the network when an HTTP endpoint is configured, and the generated sandbox policy then permits the agent to continue using that same cleartext endpoint.
  • Required action: Require HTTPS by default before reachability validation or generated policy content is produced. If HTTP is required for a local lab/private deployment, gate it behind the same explicit private-host opt-in and prove that bearer tokens are never sent to arbitrary cleartext endpoints by default.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Inspect `mattermostManifest.inputs.baseUrl.formatPattern`, `policyTemplates[0].sourceType`, and `fetchWithTimeout()` in the reachability hook; the current tests in `manifests.test.ts` and `policy-template-renderer.test.ts` also show HTTP acceptance.
  • Missing regression test: Add tests that `http://chat.example.com\` and `http://192.168.1.5:8065\` are rejected before `fetch` is called and before `renderPolicyTemplate()` returns policy content, unless an explicit reviewed opt-in is implemented.
  • Done when: The required change is committed and verification passes: Inspect `mattermostManifest.inputs.baseUrl.formatPattern`, `policyTemplates[0].sourceType`, and `fetchWithTimeout()` in the reachability hook; the current tests in `manifests.test.ts` and `policy-template-renderer.test.ts` also show HTTP acceptance.
  • Evidence: `formatPattern: "^https?://..."` and prompt help mention `http://host:port\`; `normalizeMattermostBaseUrl()` allows `http:`; `fetchWithTimeout()` always sets the bearer `Authorization` header.

PRA-7 Required — Missing Mattermost policy-template source can silently drop generated policy

  • Location: src/lib/messaging/compiler/engines/policy-template-renderer.ts:49
  • Category: correctness
  • Problem: `renderPolicyTemplate()` returns `null` when the configured `sourceInput` has no non-empty string value. The caller filters nulls out, so the plan can omit generated policy content without a targeted diagnostic from the policy-template layer.
  • Impact: If rebuild hydration, persisted state, or a future manifest change leaves Mattermost active without a renderable `baseUrl`, credentials and OpenClaw config can be planned while the required egress policy is absent or stale. Operators get a channel setup that appears enabled but cannot safely or predictably reach the intended Mattermost server.
  • Required action: Make required policy-template sources impossible to miss: either fail plan compilation with a clear diagnostic, or mark the channel inactive/skipped with an operator-visible reason before credentials, providers, registry state, or policy state are mutated. Document whether rendered template content or persisted `mattermostConfig.baseUrl` is the rebuild source of truth.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Read `renderPolicyTemplate()` and `planNetworkPolicy()` together; confirm that `null` templates are dropped and that no Mattermost-specific diagnostic is emitted for a missing template source.
  • Missing regression test: Add a compiler test where Mattermost has a bot token but no `MATTERMOST_URL`, and assert either a clear compile error or an inactive/skipped channel with no credential binding, no agent render, and no generated policy side effects.
  • Done when: The required change is committed and verification passes: Read `renderPolicyTemplate()` and `planNetworkPolicy()` together; confirm that `null` templates are dropped and that no Mattermost-specific diagnostic is emitted for a missing template source.
  • Evidence: `const sourceValue = inputStringValue(...); if (!sourceValue) return null;` is followed by `flatMap(... return rendered ? [rendered] : [])` in `planNetworkPolicy()`.

PRA-8 Required — Mattermost user-facing setup and policy behavior are undocumented

  • Location: docs/manage-sandboxes/messaging-channels.mdx:1
  • Category: docs
  • Problem: This PR adds a user-facing channel, bot-token enrollment, base URL rules, generated custom policy content, allowlist controls, and troubleshooting-relevant reachability behavior, but the messaging channel docs contain no Mattermost section.
  • Impact: Operators cannot tell which URLs are accepted, whether HTTP/private hosts are safe, how generated policy is applied or removed, what IDs to provide, or how to troubleshoot reachability failures. That is especially risky for a feature that changes sandbox egress policy and handles bot credentials.
  • Required action: Update the messaging channel documentation for Mattermost setup, OpenClaw-only scope, bot token creation, URL/security requirements, generated policy lifecycle, allowed users/channels, mention mode, troubleshooting, and any explicit opt-in behavior for private or HTTP deployments.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Search `docs/manage-sandboxes/messaging-channels.mdx` and the rest of `docs/` for `Mattermost`; the current checkout has no Mattermost documentation.
  • Missing regression test: If docs lint/frontmatter checks exist for changed docs, include the Mattermost section in that validation; otherwise the evidence is the added doc section itself plus a docs build in the normal docs workflow.
  • Done when: The required change is committed and verification passes: Search `docs/manage-sandboxes/messaging-channels.mdx` and the rest of `docs/` for `Mattermost`; the current checkout has no Mattermost documentation.
  • Evidence: The PR body marks `Docs updated for user-facing behavior changes` unchecked, and a read-only grep found no `mattermost` matches under `docs/`.

PRA-9 Resolve/justify — Mattermost reachability logs untrusted response bodies at a credential boundary

  • Location: src/lib/messaging/channels/mattermost/hooks/reachability.ts:69
  • Category: security
  • Problem: For non-401/403 failures, the hook reads up to 240 characters of the response body and includes it in operator logs. The body is controlled by the configured endpoint and is not redacted.
  • Impact: A malicious or misconfigured endpoint can reflect token-like strings, internal details, or other sensitive content into logs while NemoClaw is validating a bearer-token integration.
  • Recommended action: Log only HTTP status and a coarse failure reason by default. If body details are needed, gate them behind an explicit verbose/debug mode and redact Authorization values, bearer tokens, and common secret patterns before logging.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read the `!response.ok` branch in `createMattermostReachabilityHook()` and `readResponseText()`; confirm the detail string is appended to `logMattermostDisabled(...)` without redaction.
  • Missing regression test: Add a reachability test where the server returns a body containing `Bearer reflected-token` or `MATTERMOST_BOT_TOKEN=...`, and assert the default logs contain only status/coarse reason and no secret-like body content.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read the `!response.ok` branch in `createMattermostReachabilityHook()` and `readResponseText()`; confirm the detail string is appended to `logMattermostDisabled(...)` without redaction.
  • Evidence: `const detail = await readResponseText(response)` is interpolated into the log message; `readResponseText()` only normalizes whitespace and truncates.

PRA-10 Resolve/justify — Generated Mattermost policy lifecycle is not proven end-to-end

  • Location: src/lib/messaging/compiler/workflow-planner.ts:83
  • Category: correctness
  • Problem: The PR adds generated custom policy content, host-state merge support, add-time application, and remove-plan pruning, but the tests do not fully prove the operator lifecycle for generated policies: remove should remove the custom policy, stop should suppress application, start/rebuild should reapply from the documented source, and URL changes should not leave stale policy content.
  • Impact: Generated Mattermost policy can become orphaned, missing, or stale relative to the channel state. That can leave unnecessary sandbox egress open after removal/stop, or leave Mattermost enabled without the egress it needs after rebuild or URL changes.
  • Recommended action: Add Mattermost-specific lifecycle coverage and fix any exposed gaps: `channels remove mattermost` should remove the generated custom policy and prune `networkPolicy.templates`; stop should prevent generated policy application while preserving reusable provider state; start and rebuild/resume should reapply generated policy from the documented source of truth.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect `removePlanChannel()`, `setPlanChannelDisabled()`, `filterEnabledPlanEntries()`, `removeChannelPresetIfPresent()`, and `applyGeneratedMessagingPolicyTemplatesFromRegistry()` together; then compare with tests, which currently cover add/onboard application but not the full Mattermost custom-policy lifecycle.
  • Missing regression test: Add tests named for the lifecycle behaviors: `channels remove mattermost removes generated custom policy and prunes networkPolicy.templates`, `channels stop mattermost does not apply generated template content`, `channels start mattermost reapplies generated template content`, and `rebuild reapplies Mattermost generated policy from the documented source of truth`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect `removePlanChannel()`, `setPlanChannelDisabled()`, `filterEnabledPlanEntries()`, `removeChannelPresetIfPresent()`, and `applyGeneratedMessagingPolicyTemplatesFromRegistry()` together; then compare with tests, which currently cover add/onboard application but not the full Mattermost custom-policy lifecycle.
  • Evidence: Code now filters templates on remove and filters disabled entries at apply time, but searched tests only showed generated policy add/onboard application and generic Slack preset removal/session sync.

PRA-11 Resolve/justify — Mattermost assertions grow shared messaging test monoliths despite focused test files

  • Location: src/lib/messaging/channels/manifests.test.ts:585
  • Category: architecture
  • Problem: The PR adds focused Mattermost test files, but also grows shared manifest/compiler/setup monoliths substantially with Mattermost-specific shape assertions.
  • Impact: Shared test hotspots become harder to review and maintain, and future channel PRs already overlap these same files. This increases merge drift and makes channel-specific behavior harder to reason about.
  • Recommended action: Move most Mattermost-specific manifest and compiler shape assertions into focused Mattermost test files or small local helpers. Leave shared suites for registration, serialization, agent availability, cross-channel smoke, and security invariants that must apply to every channel.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Compare the large Mattermost block in `src/lib/messaging/channels/manifests.test.ts` and Mattermost additions in `manifest-compiler.test.ts` with the focused files under `src/lib/messaging/channels/mattermost/`.
  • Missing regression test: Existing focused Mattermost tests already cover template resolver and reachability; preserve that coverage while moving manifest/compiler shape assertions into similarly focused Mattermost test files.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Compare the large Mattermost block in `src/lib/messaging/channels/manifests.test.ts` and Mattermost additions in `manifest-compiler.test.ts` with the focused files under `src/lib/messaging/channels/mattermost/`.
  • Evidence: Synthetic drift reports `manifests.test.ts` +129 lines, `manifest-compiler.test.ts` +100 lines, and `setup-applier.test.ts` +44 lines; several open messaging channel PRs overlap these shared suites.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@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)
nemoclaw-blueprint/policies/templates/mattermost.yaml (1)

4-37: 🧹 Nitpick | 🔵 Trivial

Run the targeted network-policy-e2e slice before merge.

This change is in nemoclaw-blueprint/policies/**, so validating deny-by-default/whitelist/hot-reload/SSRF behavior is important for release confidence.

As per coding guidelines, changes under nemoclaw-blueprint/policies/** should run the network-policy-e2e job.

🤖 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-blueprint/policies/templates/mattermost.yaml` around lines 4 - 37,
Before merging this PR with changes to the Mattermost network policy
configuration in nemoclaw-blueprint/policies/templates/mattermost.yaml, run the
network-policy-e2e test slice to validate that the policy configuration
correctly enforces deny-by-default behavior, whitelist rules, hot-reload
functionality, and SSRF protection. This is required per coding guidelines for
any changes under the nemoclaw-blueprint/policies/** directory to ensure release
confidence.

Source: Coding guidelines

🤖 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 `@src/lib/messaging/channels/mattermost/hooks/reachability.ts`:
- Around line 46-47: The normalizeMattermostBaseUrl function only strips URL
suffixes but does not enforce strict validation before the baseUrl is used in
fetch requests with Authorization Bearer tokens. Add explicit validation after
the baseUrl normalization to ensure it only accepts HTTP or HTTPS schemes,
rejects URLs containing credentials, and blocks any query strings or fragment
identifiers. Apply this stricter validation at both call sites (around line
46-47 and the other location at 155-157) before the baseUrl is used in any
authenticated fetch requests.

In `@src/lib/messaging/channels/mattermost/manifest.ts`:
- Around line 89-99: The Mattermost manifest in the policyTemplates field does
not align with the standard coding guideline for channel manifests. Rename the
policyTemplates field to policyPresets to match the convention used by other
channel manifests like slack, wechat, and whatsapp. Additionally, add the
missing agentPackages field at the same level as policyPresets to complete the
required manifest structure that includes auth, inputs, credentials,
policyPresets, render, runtime, agentPackages, state, and hooks.

In `@test/channels-add-generated-policy.test.ts`:
- Around line 20-27: The env object in the spawned-script invocation spreads all
of process.env which can leak unrelated messaging credentials like TELEGRAM_*,
DISCORD_* and cause test flakiness. Remove the spread operator (...process.env)
from the env object initialization and instead explicitly include only the
specific environment variables needed for this test (such as HOME,
NEMOCLAW_NON_INTERACTIVE, NEMOCLAW_SKIP_MATTERMOST_AUTH_VALIDATION,
MATTERMOST_BOT_TOKEN, and MATTERMOST_URL). This makes the test hermetic by
preventing unrelated environment variables from affecting the spawned process
behavior.

---

Nitpick comments:
In `@nemoclaw-blueprint/policies/templates/mattermost.yaml`:
- Around line 4-37: Before merging this PR with changes to the Mattermost
network policy configuration in
nemoclaw-blueprint/policies/templates/mattermost.yaml, run the
network-policy-e2e test slice to validate that the policy configuration
correctly enforces deny-by-default behavior, whitelist rules, hot-reload
functionality, and SSRF protection. This is required per coding guidelines for
any changes under the nemoclaw-blueprint/policies/** directory to ensure release
confidence.
🪄 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: 9aac4e67-211e-4422-a0a0-9ca047855288

📥 Commits

Reviewing files that changed from the base of the PR and between 60b0a00 and 59972b1.

📒 Files selected for processing (40)
  • agents/openclaw/manifest.yaml
  • ci/test-file-size-budget.json
  • nemoclaw-blueprint/policies/templates/mattermost.yaml
  • src/lib/actions/sandbox/policy-channel.ts
  • src/lib/agent/defs.test.ts
  • src/lib/messaging-channel-config.test.ts
  • src/lib/messaging/applier/host-state-applier.ts
  • src/lib/messaging/applier/policy.ts
  • src/lib/messaging/applier/setup-applier.test.ts
  • src/lib/messaging/applier/types.ts
  • src/lib/messaging/channels/built-ins.ts
  • src/lib/messaging/channels/manifests.test.ts
  • src/lib/messaging/channels/mattermost/hooks/index.ts
  • src/lib/messaging/channels/mattermost/hooks/reachability.test.ts
  • src/lib/messaging/channels/mattermost/hooks/reachability.ts
  • src/lib/messaging/channels/mattermost/manifest.ts
  • src/lib/messaging/channels/mattermost/template-resolver.test.ts
  • src/lib/messaging/channels/mattermost/template-resolver.ts
  • src/lib/messaging/channels/metadata.test.ts
  • src/lib/messaging/channels/metadata.ts
  • src/lib/messaging/channels/template-resolver.ts
  • src/lib/messaging/compiler/engines/policy-resolver.ts
  • src/lib/messaging/compiler/engines/policy-template-renderer.test.ts
  • src/lib/messaging/compiler/engines/policy-template-renderer.ts
  • src/lib/messaging/compiler/manifest-compiler.test.ts
  • src/lib/messaging/compiler/manifest-compiler.ts
  • src/lib/messaging/compiler/workflow-planner.ts
  • src/lib/messaging/diagnostics.test.ts
  • src/lib/messaging/diagnostics.ts
  • src/lib/messaging/hooks/builtins.ts
  • src/lib/messaging/hooks/hook-runner.test.ts
  • src/lib/messaging/manifest/types.ts
  • src/lib/messaging/persistence.ts
  • src/lib/onboard.ts
  • src/lib/onboard/messaging-policy-templates.ts
  • src/lib/onboard/messaging-prep.test.ts
  • src/lib/sandbox/channels.test.ts
  • test/channels-add-generated-policy.test.ts
  • test/channels-add-preset.test.ts
  • test/sandbox-provider-cleanup.test.ts

Comment thread src/lib/messaging/channels/mattermost/hooks/reachability.ts Outdated
Comment thread src/lib/messaging/channels/mattermost/manifest.ts
Comment thread test/channels-add-generated-policy.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.

Actionable comments posted: 1

🤖 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 `@src/lib/onboard/policy-selection.ts`:
- Line 474: The call to applyGeneratedMessagingPolicyTemplatesFromRegistry is
currently placed after the syncPresetSelection call, but the function exits
early when policyMode is set to skip, none, or no (around line 408), meaning
generated messaging templates never get applied in non-interactive onboard
paths. Move the applyGeneratedMessagingPolicyTemplatesFromRegistry call to
execute before the policy mode exit condition so that generated templates are
always applied to selected channels regardless of the skip mode, ensuring
channels receive required network policy rules.
🪄 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: f660a666-35e8-4d0e-8583-da4e9822d0f1

📥 Commits

Reviewing files that changed from the base of the PR and between 59972b1 and 75b08a8.

📒 Files selected for processing (1)
  • src/lib/onboard/policy-selection.ts

Comment thread src/lib/onboard/policy-selection.ts
@sandl99 sandl99 added enhancement New capability or improvement request VRDC Issues and PRs submitted by NVIDIA VRDC test team. area: messaging Messaging channels, bridges, manifests, or channel lifecycle labels Jun 23, 2026
sandl99 and others added 2 commits June 23, 2026 22:59
…ariable'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99
sandl99 changed the base branch from main to fix/openclaw-fetch-guard-default-proxy June 24, 2026 07:57
@sandl99
sandl99 marked this pull request as draft June 26, 2026 05:58
@copy-pr-bot

copy-pr-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

cv added a commit that referenced this pull request Jun 30, 2026
## Summary

Broadens the OpenClaw compatibility patch so `resolveGuardedFetchMode()`
defaults omitted guarded-fetch modes to `trusted_env_proxy` inside
OpenShell sandboxes. This avoids local DNS lookups for bare
`fetchWithSsrFGuard` callers while preserving explicit modes and strict
behavior outside `OPENSHELL_SANDBOX=1`.

## Related Issue

Related: #396 (fetch-guard/local DNS portion only; Gemini policy/docs
remain out of scope)
Fixes #4687
Related: #5129
Related: #5592

## Changes

- Patch OpenClaw's central guarded-fetch mode resolver in the sandbox
image instead of rewriting individual call sites.
- Remove the deprecated `proxy: "env"` compatibility branch from the
patched resolver and drop the old cron-preflight call-site patch.
- Cover additional bare `fetchWithSsrFGuard` users, including the
Mattermost/OpenClaw call site discussed in #5592.
- Update fetch-guard patch regression tests for sandbox defaults,
explicit-mode precedence, out-of-sandbox strict behavior, and removal of
the narrower Patch 6 rewrite.

## Localized compatibility patch review

- **Invalid state:** OpenClaw 2026.5.27 resolves an omitted
guarded-fetch mode to strict DNS pinning. In an OpenShell proxy-only
sandbox, that performs local DNS before proxy dispatch, so sandbox-only
and proxy-routed names fail before policy enforcement.
- **Source boundary:** NemoClaw consumes the pinned compiled OpenClaw
distribution in the sandbox image; it does not own the upstream resolver
source. The image build therefore classifies and patches the reviewed
`resolveGuardedFetchMode()` shape centrally and fails closed if that
shape drifts.
- **Source-fix constraint:** The durable fix belongs in OpenClaw: either
select `trusted_env_proxy` for OpenShell sandboxes at the resolver
boundary or make every sandbox-sensitive caller pass that mode
explicitly. A permanent NemoClaw fork of the third-party runtime is out
of scope.
- **Regression proof:** `test/fetch-guard-patch-regression.test.ts`
verifies the reviewed resolver shape, explicit-mode precedence,
sandbox-only default, strict behavior outside the sandbox, removal of
the deprecated opt-in, representative SSRF denials, and fail-closed
drift handling. The exact merged head passes all 23 focused tests.
- **Removal condition:** Remove Patch 4 when the pinned OpenClaw release
provides an equivalent OpenShell-aware default, or when every
sandbox-sensitive caller explicitly selects trusted proxy mode and the
runtime acceptance checks pass without this patch.

## Security boundary and E2E

Inspection of the pinned OpenClaw 2026.5.27 implementation confirms that
explicit modes still override the default, hostname validation runs
before proxy dispatcher construction,
loopback/metadata/private/special-use IPv4 and IPv6 literals remain
rejected, and redirects are handled manually and revalidated on each
hop. DNS-resolution enforcement intentionally moves to the OpenShell L7
proxy and network-policy boundary only for omitted-mode calls inside the
sandbox.

A unified exact-head E2E dispatch covers
`cron-preflight-inference-local`, `inference-routing`, `network-policy`,
and `common-egress-agent`:
https://github.com/NVIDIA/NemoClaw/actions/runs/28424214692

## Type of Change

- [x] 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

- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal commit and push hooks passed on the current head
- [x] Targeted test passes: 23/23
- [x] Tests added or updated for changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Exact-head unified E2E is passing (in progress)

---

Signed-off-by: San Dang <sdang@nvidia.com>

---------

Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Base automatically changed from fix/openclaw-fetch-guard-default-proxy to main June 30, 2026 08:55
@sandl99 sandl99 closed this Jul 3, 2026
@sandl99
sandl99 deleted the feat/onboard-mattermost-openclaw branch July 8, 2026 03:19
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
…#5713)

## Summary

Broadens the OpenClaw compatibility patch so `resolveGuardedFetchMode()`
defaults omitted guarded-fetch modes to `trusted_env_proxy` inside
OpenShell sandboxes. This avoids local DNS lookups for bare
`fetchWithSsrFGuard` callers while preserving explicit modes and strict
behavior outside `OPENSHELL_SANDBOX=1`.

## Related Issue

Related: NVIDIA#396 (fetch-guard/local DNS portion only; Gemini policy/docs
remain out of scope)
Fixes NVIDIA#4687
Related: NVIDIA#5129
Related: NVIDIA#5592

## Changes

- Patch OpenClaw's central guarded-fetch mode resolver in the sandbox
image instead of rewriting individual call sites.
- Remove the deprecated `proxy: "env"` compatibility branch from the
patched resolver and drop the old cron-preflight call-site patch.
- Cover additional bare `fetchWithSsrFGuard` users, including the
Mattermost/OpenClaw call site discussed in NVIDIA#5592.
- Update fetch-guard patch regression tests for sandbox defaults,
explicit-mode precedence, out-of-sandbox strict behavior, and removal of
the narrower Patch 6 rewrite.

## Localized compatibility patch review

- **Invalid state:** OpenClaw 2026.5.27 resolves an omitted
guarded-fetch mode to strict DNS pinning. In an OpenShell proxy-only
sandbox, that performs local DNS before proxy dispatch, so sandbox-only
and proxy-routed names fail before policy enforcement.
- **Source boundary:** NemoClaw consumes the pinned compiled OpenClaw
distribution in the sandbox image; it does not own the upstream resolver
source. The image build therefore classifies and patches the reviewed
`resolveGuardedFetchMode()` shape centrally and fails closed if that
shape drifts.
- **Source-fix constraint:** The durable fix belongs in OpenClaw: either
select `trusted_env_proxy` for OpenShell sandboxes at the resolver
boundary or make every sandbox-sensitive caller pass that mode
explicitly. A permanent NemoClaw fork of the third-party runtime is out
of scope.
- **Regression proof:** `test/fetch-guard-patch-regression.test.ts`
verifies the reviewed resolver shape, explicit-mode precedence,
sandbox-only default, strict behavior outside the sandbox, removal of
the deprecated opt-in, representative SSRF denials, and fail-closed
drift handling. The exact merged head passes all 23 focused tests.
- **Removal condition:** Remove Patch 4 when the pinned OpenClaw release
provides an equivalent OpenShell-aware default, or when every
sandbox-sensitive caller explicitly selects trusted proxy mode and the
runtime acceptance checks pass without this patch.

## Security boundary and E2E

Inspection of the pinned OpenClaw 2026.5.27 implementation confirms that
explicit modes still override the default, hostname validation runs
before proxy dispatcher construction,
loopback/metadata/private/special-use IPv4 and IPv6 literals remain
rejected, and redirects are handled manually and revalidated on each
hop. DNS-resolution enforcement intentionally moves to the OpenShell L7
proxy and network-policy boundary only for omitted-mode calls inside the
sandbox.

A unified exact-head E2E dispatch covers
`cron-preflight-inference-local`, `inference-routing`, `network-policy`,
and `common-egress-agent`:
https://github.com/NVIDIA/NemoClaw/actions/runs/28424214692

## Type of Change

- [x] 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

- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal commit and push hooks passed on the current head
- [x] Targeted test passes: 23/23
- [x] Tests added or updated for changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Exact-head unified E2E is passing (in progress)

---

Signed-off-by: San Dang <sdang@nvidia.com>

---------

Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: messaging Messaging channels, bridges, manifests, or channel lifecycle enhancement New capability or improvement request VRDC Issues and PRs submitted by NVIDIA VRDC test team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant