Skip to content

feat(diagnostics): add the managed-transport failure contract - #8725

Open
JulienAu wants to merge 11 commits into
NVIDIA:mainfrom
JulienAu:feat/managed-transport-diagnostics
Open

feat(diagnostics): add the managed-transport failure contract#8725
JulienAu wants to merge 11 commits into
NVIDIA:mainfrom
JulienAu:feat/managed-transport-diagnostics

Conversation

@JulienAu

@JulienAu JulienAu commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

First slice of #7957: the reusable failure-only diagnostic contract for managed outbound transports. It defines the managed_transport_failure event schema with the seven connection-ordered phases from the issue, builds events through an allowlist-only constructor so authorization material, cookies, tokens, query strings, request bodies, and session identifier values can never reach an event, and emits stable key=value lines with a generated correlation id on failure only. A non-MCP webhook consumer test proves the contract is reusable beyond the first integration. The OpenClaw remote MCP dist-patch integration and the CLI/docs surface follow as the next two slices per the plan on the issue.

Related Issue

Refs #7957 (sequential PR 1 of 3; claimed on the issue, prior interested commenter confirmed they are not working on it)

Changes

  • Add src/lib/diagnostics/managed-transport.ts: ManagedTransportFailure schema and phase type; buildManagedTransportFailure (allowlist-only; requirement: the issue's redaction constraints; consumers: the slice-2 MCP dist patch plus any managed outbound transport; a direct change is impossible because no shared contract exists today; protected by the negative tests below); safeCauseChain (keeps name/code/errno/syscall/port, deliberately drops free-text messages because undici embeds URLs and header values in them, cycle-guarded, depth-bounded); safeTargetRef (credential/query/fragment stripping for URL and non-URL endpoint strings; the URL parse path is restricted to http/https because new URL("user:secret@host") parses with scheme user: and would leak the credential); pickSafeResponseHeaders (server, via, x-request-id, x-envoy-response-flags only); boundedErrorBodySnippet (512-char cap, textual content types only, defense-in-depth through the existing sanitizeTraceAttributes); classifyTransportPhase (deterministic over the undici/socket vocabulary); emitManagedTransportFailure (failure-only, injectable writer). Placement follows the issue's "observability/networking layer" wording; glad to move it beside trace.ts if preferred, per the open question on the issue.
  • Add src/lib/diagnostics/managed-transport.test.ts: 14 deterministic tests including one negative test per forbidden field class (authorization header, cookie, token in query string, URL userinfo, session identifier value), a log-injection test proving delimiter- and credential-bearing values cannot forge records, and the non-MCP example consumer required by acceptance criterion 6.

Type of Change

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

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification: no user-facing surface yet; the collection/interpretation documentation is slice 3 of the issue plan, tied to the CLI presentation.
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: security review completed with no blocking findings: feat(diagnostics): add the managed-transport failure contract #8725 (comment)
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: no-docs-needed
  • Evidence: new internal library module and tests; no user-facing surface changes. Docstrings on the module reviewed against the writing rules.
  • Agent: Codex Desktop

DGX Station Hardware Evidence

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

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run validate:pr passed after refreshing origin/main when hooks were skipped or unavailable — ran npm run validate:pr; every hook passes except hadolint, which reports a pre-existing info-level finding (Dockerfile:1543 SC2015) that is byte-identical on unmodified main; this PR changes no Dockerfile
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result: npx vitest run --project cli src/lib/diagnostics/managed-transport.test.ts; 21 tests pass. CLI typecheck, repository hooks, source-shape checks, test-size checks, and secret scanning pass.
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result:
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: JulienAu 16043912+JulienAu@users.noreply.github.com

Summary by CodeRabbit

  • Reliability

    • Improved diagnostics for managed transport failures, including phase classification and trace IDs to support troubleshooting.
    • Diagnostic records now safely handle malformed or unexpected error details.
  • Security

    • Sensitive information such as credentials, tokens, cookies, signatures, query data, and network addresses is removed from failure diagnostics.
    • Error details and response headers are limited and sanitized to prevent unsafe log content.
  • Bug Fixes

    • Prevented successful requests from generating unnecessary failure diagnostics.
    • Improved consistency and stability of transport failure reporting.

First slice of the correlated outbound diagnostics facility: a shared
managed_transport_failure event schema with seven connection-ordered
phases, an allowlist-only builder, a safe error-cause-chain walker that
drops free-text messages, credential and query stripping for endpoint
references, a bounded content-type-aware error-body snippet, a strict
response-header allowlist, deterministic phase classification over the
undici and socket vocabulary, and failure-only key=value emission with
a generated correlation id. A non-MCP webhook consumer test proves the
contract is reusable beyond the first integration. Negative tests
cover every forbidden field class.

Refs NVIDIA#7957

Signed-off-by: JulienAu <16043912+JulienAu@users.noreply.github.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Aug 10, 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 a managed transport diagnostics module. It defines sanitized failure records, classifies transport phases, builds traceable failure events, emits stable output, and tests managed transport and webhook usage.

Changes

Managed transport diagnostics

Layer / File(s) Summary
Failure contracts and sanitization
src/lib/diagnostics/managed-transport.ts, src/lib/diagnostics/managed-transport.test.ts
Defines failure types and sanitizes targets, cause chains, response headers, and textual error bodies.
Failure classification and construction
src/lib/diagnostics/managed-transport.ts, src/lib/diagnostics/managed-transport.test.ts
Classifies transport failures and builds bounded records with trace IDs, elapsed time, session status, and cause codes.
Stable diagnostic emission
src/lib/diagnostics/managed-transport.ts, src/lib/diagnostics/managed-transport.test.ts
Encodes fields and emits stable key/value diagnostics. Tests delimiter protection, credential redaction, and webhook reuse.

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

Sequence Diagram(s)

sequenceDiagram
  participant WebhookConsumer
  participant classifyTransportPhase
  participant buildManagedTransportFailure
  participant emitManagedTransportFailure
  participant stderr
  WebhookConsumer->>classifyTransportPhase: transport failure context
  classifyTransportPhase-->>WebhookConsumer: failure phase
  WebhookConsumer->>buildManagedTransportFailure: failure input
  buildManagedTransportFailure-->>WebhookConsumer: sanitized failure event
  WebhookConsumer->>emitManagedTransportFailure: failure event
  emitManagedTransportFailure->>stderr: stable diagnostic lines
Loading

Possibly related issues

Suggested labels: security

Suggested reviewers: cv

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding the managed-transport failure diagnostic contract.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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

🤖 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/diagnostics/managed-transport.ts`:
- Around line 94-106: Update the cause-chain traversal loop in the managed
transport serializer to count every visited object independently of
chain.length, including empty cause objects. Stop traversal after
MAX_CAUSE_DEPTH hops while preserving the existing seen-cycle protection and
retained SafeTransportCause entries.
- Around line 147-171: Extend classifyTransportPhase with explicit
proxy-connection context and check it before the existing app-connect error-code
matching, returning "proxy_connect" for proxy failures. Update callers to
provide that context when applicable, and add coverage for proxied timeout or
refusal while preserving direct connection classification as "app_connect".
- Around line 118-123: In src/lib/diagnostics/managed-transport.ts:118-123,
replace raw allowlisted response-header values with bounded classifications or
presence indicators, retaining identifier values only when they match a safe
grammar; reject or encode whitespace and control characters. In
src/lib/diagnostics/managed-transport.ts:99-103, constrain or omit arbitrary
cause fields such as name, code, and syscall before they reach diagnostics. In
src/lib/diagnostics/managed-transport.ts:236-238, ensure dynamic values passed
to push cannot introduce additional key=value fields or log lines, and add
adversarial coverage for tokens and line breaks in allowed headers and cause
values.
🪄 Autofix

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: 0236d64f-a048-4015-ba55-e6c7d59f54dc

📥 Commits

Reviewing files that changed from the base of the PR and between b414e22 and c47d87a.

📒 Files selected for processing (2)
  • src/lib/diagnostics/managed-transport.test.ts
  • src/lib/diagnostics/managed-transport.ts

Comment thread src/lib/diagnostics/managed-transport.ts
Comment thread src/lib/diagnostics/managed-transport.ts Outdated
Comment thread src/lib/diagnostics/managed-transport.ts
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Blocking findings reported

Advisor assessment: Blockers require maintainer review
Next action: Review the blockers below.
Findings: 1 blocker · 1 warning · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · high confidence · 1 blocker · 1 warning · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Model comparison: normalized findings differ; normalized terminology decisions differ; normalized E2E selections differ; Nemotron reported 1 fewer blocker, 1 fewer warning, the same number of suggestions.

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

2 semantic terminology decisions

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

  • established — managed transport at src/lib/diagnostics/managed-transport.ts:41: Use `managed transport` consistently for this existing diagnostic domain.
  • define — failure-only diagnostic contract at src/lib/diagnostics/managed-transport.ts:9: Define the term at first use as diagnostics emitted only for failed operations; retain the concrete contrast with success timing.

E2E guidance

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

Recommended E2E: None

1 optional E2E recommendation
  • mcp-bridge

Blockers

PRA-2 Blocker — Remove every userinfo segment from endpoint references

  • Location: src/lib/diagnostics/managed-transport.ts:91
  • Category: security
  • Problem: The non-URL fallback removes text only through the first `@`. A proxy or target such as `user:secret@second-secret@host` retains `second-secret@host` and can reach the event and emitted diagnostics.
  • Impact: An attacker-controlled or malformed endpoint can disclose credential-like userinfo in diagnostic records, crossing the credential logging boundary.
  • Fix: For non-URL values, remove text through the final `@`, or reject values that contain more than one `@`, before redaction and event construction.
  • Verification: Construct an event with `target` and `proxy` set to `user:secret@second-secret@host`; inspect the event and emitted line for either userinfo segment.
  • Test coverage: Add tests for multi-`@` proxy and target inputs that prove the built event and emitted lines contain no userinfo or credential text.
  • Evidence: `src/lib/diagnostics/managed-transport.ts:91` removes only the prefix ending at the first `@`. `src/lib/diagnostics/managed-transport.ts:267-268` uses `safeTargetRef` for proxy and target event fields. `src/lib/diagnostics/managed-transport.ts:327-328` emits proxy and target fields. `src/lib/diagnostics/managed-transport.test.ts:28-30` covers only a single `@` non-URL value.
1 warning · 0 suggestions

Warnings

Warnings do not block.

PRA-1 Warning — Connect the managed transport contract to the built transport path

  • Location: src/lib/diagnostics/managed-transport.ts:1
  • Category: architecture
  • Problem: The new diagnostic contract has no production consumer. The built sandbox stages and runs the separate inline implementation in `scripts/patch-openclaw-managed-transport-diagnostics.mts`, so this module does not change managed transport diagnostics.
  • Impact: The intended hardening does not affect the managed transport path. The two implementations can also diverge as either changes.
  • Recommendation: Make the staged managed transport path use this contract, or remove this unintegrated module and apply the required changes to the active patch implementation.
  • Verification: Search production imports of `src/lib/diagnostics/managed-transport.ts` and inspect the staged sandbox sources in `src/lib/sandbox/build-context.ts`.
  • Test coverage: Add an integration test that builds or inspects the staged managed transport patch and proves it invokes the shared failure contract for a failed request.
  • Evidence: `src/lib/diagnostics/managed-transport.ts:1` introduces the unreferenced module. `src/lib/sandbox/build-context.ts:395-396` copies `patch-openclaw-managed-transport-diagnostics.mts` into the build context. `scripts/patch-openclaw-managed-transport-diagnostics.mts:1-180` defines an independent managed transport diagnostic implementation.

Workflow run details

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

The advisor's PRA-1 blocker is right: the formatter wrote allowlisted
header values and required string fields as raw key=value text, so a
delimiter- or credential-bearing upstream value could forge a second
record or leak. Route every emitted string through encodeLogField,
which redacts through the shared trace sanitizer, bounds length, and
JSON-quotes any value carrying a control character, whitespace, quote,
or separator. Add a formatter test with newline, CRLF, forged-field,
and credential-shaped values proving one-record, no-leak output.

Refs NVIDIA#7957

Signed-off-by: JulienAu <16043912+JulienAu@users.noreply.github.com>
@JulienAu

Copy link
Copy Markdown
Contributor Author

Fixed the PRA-1 blocker in 0daaa57. Every emitted string field now goes through a single encodeLogField policy: it redacts through the shared trace sanitizer, bounds length to 256, and JSON-quotes any value carrying a control character, whitespace, quote, or =, so a delimiter- or credential-bearing upstream value cannot inject a line break or forge a second field. That covers the allowlisted response headers and the required context fields alike.

Added a formatter test that builds the event with a newline-plus-phase=policy operation, a CRLF-bearing x-request-id, and a bearer-token-shaped via, then asserts one physical line, the forged fragments confined inside quoted tokens, and the credential redacted. Full suite passes in normal and shuffled order; lint, typecheck, and repository checks are green. The three terminology decisions need no change.

@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/diagnostics/managed-transport.ts`:
- Around line 288-290: Update the errorBodySnippet formatting in the managed
transport failure emitter to pass event.errorBodySnippet through the shared
encodeLogField policy instead of JSON.stringify, preserving the existing
conditional and output field. Add a direct-emitter test using a
credential-shaped oversized snippet that verifies redaction and the
256-character limit.
🪄 Autofix

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: baf7a18b-3c70-483e-8472-833ab4d83468

📥 Commits

Reviewing files that changed from the base of the PR and between c47d87a and 0daaa57.

📒 Files selected for processing (2)
  • src/lib/diagnostics/managed-transport.test.ts
  • src/lib/diagnostics/managed-transport.ts

Comment thread src/lib/diagnostics/managed-transport.ts Outdated
Addresses the advisor's PRA-2 blocker: redaction happened only in the
line formatter, so an alternate consumer serializing the built event
could disclose a credential embedded in an operation, route, consumer
name, or allowlisted header. Redact every untrusted string field in
buildManagedTransportFailure so the returned object is safe by
construction; emission encoding stays as defense in depth. Also select
the first cause-chain code for the top-level cause_code so a wrapped
transport error surfaces its network code (advisor PRA-1 correctness).

Refs NVIDIA#7957

Signed-off-by: JulienAu <16043912+JulienAu@users.noreply.github.com>
@JulienAu

Copy link
Copy Markdown
Contributor Author

Addressed both findings from the latest advisor pass in 007583c:

  • PRA-2 (blocker): redaction now happens in buildManagedTransportFailure, not only in the formatter. Every untrusted string field (consumer, operation, route, proxy, target, and the allowlisted response headers) is redacted through the shared trace sanitizer at build time, so the returned event object is safe to serialize or forward without the line formatter. Emission encoding stays as defense in depth. Added a test asserting a credential in operation and in x-request-id is absent from the built object before any formatting.
  • PRA-1 (correctness): cause_code now selects the first cause-chain entry that carries a code, so a wrapped transport error surfaces its nested network code at the top level. Added a nested-cause test proving ECONNREFUSED is exposed.

16 tests pass in normal and shuffled order; lint, typecheck, and repository checks are green. The terminology decisions need no change.

@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/diagnostics/managed-transport.ts`:
- Around line 203-225: Update buildManagedTransportFailure to pass an explicitly
supplied input.traceId through redactField before returning it, while preserving
generateTransportTraceId() for missing IDs. Extend the built-object
serialization test to verify caller-provided trace IDs are redacted.
🪄 Autofix

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: e7d12b6e-8b68-4e9c-9f99-7b3dcd77d8f0

📥 Commits

Reviewing files that changed from the base of the PR and between 0daaa57 and 007583c.

📒 Files selected for processing (2)
  • src/lib/diagnostics/managed-transport.test.ts
  • src/lib/diagnostics/managed-transport.ts

Comment thread src/lib/diagnostics/managed-transport.ts
Addresses the advisor's PRA-3 blocker and trace-id warning: copied
error names, codes, and syscalls are now bounded identifier tokens
(anything longer or carrying other characters becomes <invalid>), and
a supplied trace id is kept only when it matches the safe id shape,
falling back to a generated one otherwise. The built event stays safe
to serialize regardless of what an upstream library or caller puts in
error metadata. Builder tests cover credential-shaped and
delimiter-bearing cause fields and trace ids.

Refs NVIDIA#7957

Signed-off-by: JulienAu <16043912+JulienAu@users.noreply.github.com>
@JulienAu

Copy link
Copy Markdown
Contributor Author

Two things.

First, the advisor's PRA-3 blocker and the trace-id and cause-code findings are addressed in 3106eba: copied error names/codes/syscalls are now bounded identifier tokens, a supplied trace id is validated at build time, and cause_code selects the first coded cause. 18 tests, green in normal and shuffled order.

Second, and more important: the advisor's architecture warning led me to scripts/patch-openclaw-managed-transport-diagnostics.mts, landed by #8204 on Aug 4 and already wired into the Dockerfile. That is the OpenClaw MCP integration this issue asked for, and it already owns the managed_transport_failure event name. I missed it when I picked this up. Apologies for the duplicate contract; my mistake.

The two are not identical: the staged patch is JS injected into the OpenClaw sandbox bundle (it cannot import src/lib), and uses transport_phase plus a managed_transport_shadow event. My module is a TypeScript contract for the in-process NemoClaw side (messaging, providers, webhooks - acceptance criteria 6-7), which the patch does not cover. But it should not define a second, incompatible schema for the same event.

I'd rather you decide the shape than force one. Options as I see them:

  1. I rework this into an in-process consumer that adopts the staged patch's canonical field set, phase vocabulary, and event names, so the two correlate. I'd add the contract test the advisor suggested comparing representative records from both.
  2. Close this as superseded by feat(observability): add managed outbound transport diagnostics #8204 if the in-process side is not wanted yet.

Which do you prefer?

@wscurran wscurran added area: networking DNS, proxy, TLS, ports, host aliases, or connectivity area: observability Logging, metrics, tracing, diagnostics, or debug output feature PR adds or expands user-visible functionality labels Aug 10, 2026
@apurvvkumaria apurvvkumaria self-assigned this Aug 11, 2026
@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Maintainer architecture decision required

The author identified that merged PR #8204 already defines and ships the canonical OpenClaw managed-transport diagnostic event, with a different field set, phase vocabulary, and event naming. This PR proposes a separate in-process TypeScript contract for NemoClaw consumers.

Two materially different directions remain:

  • Rework this PR to adopt and contract-test the existing canonical schema for in-process consumers.
  • Close it if the in-process surface is not wanted yet.

The PR is not conclusively superseded: #8204 covers the injected OpenClaw runtime path, while this branch targets in-process NemoClaw consumers. Closing it now would require an architecture and scope judgment. I am therefore leaving it open, assigning the release target, and deferring implementation, security sign-off, approval, and merge until a maintainer chooses the contract direction.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Note

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

@coderabbitai coderabbitai Bot 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

🧹 Nitpick comments (2)
src/lib/diagnostics/managed-transport.test.ts (2)

57-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the exact cause-chain depth bound.

Line 65 asserts toBeLessThanOrEqual(8). That assertion also passes if the chain collapses to zero or one entry, so a regression that drops causes stays hidden. MAX_CAUSE_DEPTH is a bounded-output guarantee. Assert the exact length, and assert the retained entries.

♻️ Proposed change
     let deep: Record<string, unknown> = { name: "leaf" };
     for (let index = 0; index < 20; index += 1) deep = { name: `n${index}`, cause: deep };
-    expect(safeCauseChain(deep).length).toBeLessThanOrEqual(8);
+    const chain = safeCauseChain(deep);
+    expect(chain).toHaveLength(8);
+    expect(chain[0]).toEqual({ name: "n19" });
+    expect(chain[7]).toEqual({ name: "n12" });

Confirm that MAX_CAUSE_DEPTH is 8 in src/lib/diagnostics/managed-transport.ts before applying the diff.

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

In `@src/lib/diagnostics/managed-transport.test.ts` around lines 57 - 66, Update
the deep-chain assertions in the test "guards against cause cycles and unbounded
depth" to verify exactly MAX_CAUSE_DEPTH entries, confirming that
MAX_CAUSE_DEPTH is 8 in managed-transport.ts first. Assert the retained entries
as well, preserving the expected newest-to-oldest cause order so regressions
that drop causes are detected.

291-301: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Assert that phase= appears exactly once.

The comment on line 296 states that the genuine phase field "appears once as a real top-level field". The assertion on line 297 only proves presence. If the encoder stopped quoting the injected operation value, the line would contain both phase=response_headers and a forged phase=policy, and the test would still pass. This is the central claim of the log-injection test.

♻️ Proposed change
-    expect(line).toContain("phase=response_headers");
+    expect(line).toContain("phase=response_headers");
+    expect(line.match(/(?:^| )phase=/g)).toHaveLength(1);
+    expect(line).not.toContain(" phase=policy");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/diagnostics/managed-transport.test.ts` around lines 291 - 301, Update
the assertions in the managed transport test around the `phase=response_headers`
check to verify that the `phase=` token occurs exactly once in the encoded line,
while preserving the existing checks for the quoted operation and request ID
values.

Source: Path instructions

🤖 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/diagnostics/managed-transport.test.ts`:
- Around line 236-269: Remove the duplicate schema assertions in the
emitManagedTransportFailure test, or update them to match the shipped
managed_transport_failure helper’s contract. Use the runtime helper’s emitted
fields and event format as the source of truth, eliminating unsupported fields
such as phase, trace_id, and cause_chain from this test.

---

Nitpick comments:
In `@src/lib/diagnostics/managed-transport.test.ts`:
- Around line 57-66: Update the deep-chain assertions in the test "guards
against cause cycles and unbounded depth" to verify exactly MAX_CAUSE_DEPTH
entries, confirming that MAX_CAUSE_DEPTH is 8 in managed-transport.ts first.
Assert the retained entries as well, preserving the expected newest-to-oldest
cause order so regressions that drop causes are detected.
- Around line 291-301: Update the assertions in the managed transport test
around the `phase=response_headers` check to verify that the `phase=` token
occurs exactly once in the encoded line, while preserving the existing checks
for the quoted operation and request ID values.
🪄 Autofix

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: 1af6305e-5243-4642-bd0c-cb0e42baf028

📥 Commits

Reviewing files that changed from the base of the PR and between d357554 and 99523ed.

📒 Files selected for processing (2)
  • src/lib/diagnostics/managed-transport.test.ts
  • src/lib/diagnostics/managed-transport.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/diagnostics/managed-transport.ts

Comment thread src/lib/diagnostics/managed-transport.test.ts
cv and others added 3 commits August 10, 2026 23:50
…ippet

Addresses both advisor warnings on the managed-transport failure contract.

PRA-1: buildManagedTransportFailure accepted an error body with no condition
on the HTTP status, while boundedErrorBodySnippet documents non-2xx capture
only. A caller could therefore attach the body of a successful response to
failure diagnostics and retain response content the module promises not to
keep. The snippet is now carried only when httpStatus is present and outside
200-299. An absent status is not treated as a failure status either: a
transport error that never produced a response has no body to capture.

PRA-2: the emitter serialized errorBodySnippet with JSON.stringify while
every other field went through encodeLogField. JSON.stringify quotes and
escapes, so it prevented record forging, but it neither redacts nor bounds.
An event object constructed directly rather than through the builder could
therefore carry a credential-bearing snippet straight into diagnostic output,
bypassing the build-time redaction boundary. The snippet now goes through
encodeLogField like everything else. encodeLogField takes an optional bound
so the snippet keeps its documented 512-character limit rather than being
truncated to the 256-character field limit.

Two regression tests, both verified to fail without their fix: a builder test
asserting a 200 response with a textual body yields no snippet and does not
serialize its content, and an emitter test passing a hand-constructed event
whose snippet carries a bearer token and a forged event line, asserting the
credential is absent, the record count is unchanged, and no newline escapes.

20 tests pass in normal and shuffled order. Biome check and the src
typecheck are clean; the two pre-existing banner.ts errors about an unbuilt
nemoclaw/dist artifact reproduce identically on an unmodified tree.

Signed-off-by: JulienAu <16043912+JulienAu@users.noreply.github.com>
@JulienAu

Copy link
Copy Markdown
Contributor Author

Both advisor warnings from the latest pass are addressed in e14b0c4. Neither blocked, but one is a real gap in the redaction boundary, so I would rather not leave it open while the architecture question is pending.

PRA-2 (security). The emitter serialized errorBodySnippet with JSON.stringify while every other field went through encodeLogField. That quotes and escapes, so record forging was already prevented, but it neither redacts nor bounds. An event object constructed directly rather than through buildManagedTransportFailure could therefore carry a credential-bearing snippet straight into diagnostic output, bypassing the build-time redaction boundary added in 007583c. The snippet now goes through encodeLogField like everything else. encodeLogField takes an optional bound so the snippet keeps its documented 512-character limit instead of being truncated to the 256-character field limit.

PRA-1 (correctness). buildManagedTransportFailure accepted an error body with no condition on the HTTP status, while boundedErrorBodySnippet documents non-2xx capture only. A caller could attach a successful response body to failure diagnostics. The snippet is now carried only when httpStatus is present and outside 200-299. An absent status is not treated as a failure status either: a transport error that never produced a response has no body to capture.

Both regression tests were verified to fail without their fix, not merely to pass with it: reverting either change alone turns exactly one of them red. The builder test asserts a 200 response with a textual body yields no snippet and does not serialize its content; the emitter test passes a hand-constructed event whose snippet carries a bearer token and a forged event line, then asserts the credential is absent, the record count is unchanged, and no newline escapes.

20 tests pass in normal and shuffled order. Biome check and the tsconfig.src.json typecheck are clean; the two src/lib/cli/banner.ts errors about the unbuilt nemoclaw/dist/shared/banner-boundary.cjs artifact reproduce identically on an unmodified tree.

On the architecture decision itself: nothing here presumes an outcome. The encoding policy and the body-capture restriction hold whichever direction you choose, including a rework onto the canonical schema from #8204, since both are properties of how values are emitted rather than of the field set. Still happy to close this as superseded if the in-process surface is not wanted yet.

@apurvvkumaria

Copy link
Copy Markdown
Collaborator

Security review completed for revision 4783135b5.

No blocking findings were identified across the repository's nine review categories. The follow-up keeps supplied correlation IDs only when they match the allowed shape and the shared sanitizer leaves them unchanged; credential-shaped values are replaced before the event can be serialized. Explicit proxy-connection context now maps to proxy_connect without changing network behavior.

The change adds no credential custody, authentication, file-permission, subprocess, dependency, SSRF, or network-policy surface. Focused validation passed: 21 tests, CLI typecheck, repository hooks, and secret scanning. The documentation writer found no user-facing documentation change because this module still has no production importer.

@prekshivyas prekshivyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Architecture/product-scope blocker on latest PR commit 4783135b5.

This adds a second managed-transport diagnostic contract while the shipped OpenClaw helper from #8204 remains the production source of truth with incompatible event fields and phase vocabulary. The new 349-line module also has no production importer, so merging it now creates two contracts without completing a migration.

Please choose one canonical direction before landing this slice: either adapt and contract-test the shipped schema for in-process consumers, or migrate the existing production helper and consumer to this schema in the same change. The maintainer architecture comment on this PR records the same unresolved choice; the security review passing does not resolve that product decision.

@JulienAu

Copy link
Copy Markdown
Contributor Author

The canonical-direction question from the architecture review now has a concrete answer in #8964: the contract adopts the dist patch's documented wire vocabulary (transport_phase, session_present, phase value connect), keeps trace_id distinct from the patch's documented local diagnostic_id, and adds a contract test that reads the patch source so the two cannot diverge silently again. Stacked on this branch; I will rebase it onto main after this PR merges.

@senthilr-nv

Copy link
Copy Markdown
Collaborator

Additional verified security finding on latest PR commit 4783135b50d088c01a5b043179683575cc8a758c.

safeTargetRef removes non-URL userinfo only through the first @. The input user:secret@second-secret@host:8080?token=x returns second-secret@host:8080. buildManagedTransportFailure uses this result for both proxy and target, so credential-like userinfo can reach the event and emitted diagnostics.

The endpoint sanitizer must remove text through the final @, or reject values that contain multiple @ characters. Add proxy and target tests that verify the built event and emitted records contain neither userinfo segment.

This security finding is independent of the existing architecture and product-scope blocker. Resolving it does not select the canonical contract direction.

@apurvvkumaria apurvvkumaria added the needs: design Requires product or architecture direction label Aug 13, 2026
@apurvvkumaria

apurvvkumaria commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Large-change flag: this revision adds 779 lines.

The canonical-schema decision remains unresolved. The latest security review also confirmed that endpoint values containing multiple @ characters can expose credential-like userinfo in diagnostics. PR #8964 contains the sanitizer hardening but still has no production consumer and does not resolve the architecture choice. This PR must not merge unless maintainers select an authoritative implementation, integrate its consumer, fix the redaction boundary, update documentation, and rerun security review and all required gates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: networking DNS, proxy, TLS, ports, host aliases, or connectivity area: observability Logging, metrics, tracing, diagnostics, or debug output feature PR adds or expands user-visible functionality needs: design Requires product or architecture direction v0.0.109 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants