Skip to content

fix: address SonarCloud quality gate issues#789

Merged
yacosta738 merged 7 commits into
mainfrom
fix/sonarcloud-quality-gate-cleanup
May 6, 2026
Merged

fix: address SonarCloud quality gate issues#789
yacosta738 merged 7 commits into
mainfrom
fix/sonarcloud-quality-gate-cleanup

Conversation

@yacosta738
Copy link
Copy Markdown
Contributor

Related Issues

SonarCloud quality gate: https://sonarcloud.io/project/overview?id=dallay_corvus


Summary

  • Fixes the failing Dream duplicate-trigger test by using the existing transient-lock retry helper before asserting session processing.
  • Reduces SonarCloud cognitive-complexity issues in gateway stream handling, dashboard SSE parsing, and release component expansion without changing runtime contracts.
  • Addresses SonarCloud regex/security-hotspot findings in release scripts and the Rook Dockerfile by simplifying regex parsing, using trusted PATH values in tests, and disabling recommended apt packages.

Tested Information

  • cargo clippy --manifest-path "clients/agent-runtime/Cargo.toml" --all-targets -- -D warnings
  • cargo test --manifest-path "clients/agent-runtime/Cargo.toml" --lib gateway::
  • cargo test --manifest-path "clients/agent-runtime/Cargo.toml" --lib memory::dream::tests::suppresses_duplicate_triggers_by_session_id -- --exact
  • node --test "scripts/release-contract.test.mjs"
  • pnpm --filter @corvus/dashboard run check
  • Pre-push hook passed, including Rust checks/tests and web lint/checks.

Review path: start with scripts/release-contract.test.mjs and the release resolver changes, then review the stream parsing/dispatch helper extraction.


Documentation Impact

  • Docs updated in: N/A
  • No docs update required because: changes are test hardening, quality-gate refactors, and Docker/package-install hygiene without user-facing behavior or configuration changes.
  • I verified the documentation matches the current behavior.

Breaking Changes

None.


Checklist

  • I have checked that there isn’t already a PR solving the same problem.
  • I have read the Contributing Guidelines.
  • I ensured my code follows the project's style guidelines.
  • I have added or updated tests that prove my fix is effective or that my feature works.
  • I have updated the documentation, or I explained above why no documentation update is needed.
  • I verified the documentation matches the current behavior.
  • I have documented any breaking changes in the Breaking Changes section.
  • I have linked the related issue (if any).

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

Warning

Rate limit exceeded

@yacosta738 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 14 seconds before requesting another review.

To continue reviewing without waiting, purchase usage credits in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7dc27206-1804-4d09-8dc4-d332dc8e6c2e

📥 Commits

Reviewing files that changed from the base of the PR and between 0a966cb and 6fab139.

📒 Files selected for processing (7)
  • clients/agent-runtime/src/gateway/mod.rs
  • clients/agent-runtime/src/skills/mod.rs
  • clients/rook/Dockerfile
  • clients/web/apps/dashboard/src/composables/useChat.spec.ts
  • clients/web/apps/dashboard/src/composables/useChat.ts
  • scripts/release-contract.test.mjs
  • scripts/resolve-release-components.mjs
📝 Walkthrough

Walkthrough

Introduces a dispatcher-based streaming path in the agent gateway, refactors client-side streaming parsing, hardens skill path handling and recursive copy safety, improves a Dream test for transient lock contention, and updates release/test tooling and a Docker builder step.

Changes

Agent Runtime — Streaming Dispatcher

Layer / File(s) Summary
Types & Outcome Mapping
clients/agent-runtime/src/gateway/mod.rs
Adds StreamProcessingOutcome enum and StreamDispatcherRequest<'a> to model dispatcher streaming requests and SSE-friendly outcomes.
Dispatcher Execution
clients/agent-runtime/src/gateway/mod.rs
Adds execute_stream_dispatcher() which delegates to webhook_dispatch::execute and maps WebhookTurnResult to StreamProcessingOutcome.
Routing Integration
clients/agent-runtime/src/gateway/mod.rs
Refactors handle_chat_stream() to branch on dispatcher-enabled flag; builds StreamDispatcherRequest and routes to the new dispatcher path, falling back to legacy HTTP ingress when disabled; preserves SSE semantics and session updates.

Agent Runtime — Skills & Memory Safety

Layer / File(s) Summary
Canonicalization & Copy Helpers
clients/agent-runtime/src/skills/mod.rs
Adds copy_dir_recursive() and copy_dir_recursive_checked() with canonical-path checks to reject symlink escapes and loops.
Skill Load/Validation
clients/agent-runtime/src/skills/mod.rs
Canonicalizes SKILL.md and skill dir paths, enforces SKILL.md inside skill dir, derives name/description from frontmatter with canonical fallbacks, stores canonical path in Skill.location.
Tests / Concurrency
clients/agent-runtime/src/skills/mod.rs, clients/agent-runtime/src/memory/dream.rs
Adds tests for symlink-escape and symlink-loop behaviors; updates Dream test to use run_if_triggered_after_transient_busy() and assert lock state before proceeding.

Web Dashboard — Streaming Pipeline Refactor

Layer / File(s) Summary
Streaming Types
clients/web/apps/dashboard/src/composables/useChat.ts
Adds StreamReadResult to capture final done-event separately from streaming loop.
Line/Event Parsing
clients/web/apps/dashboard/src/composables/useChat.ts
Introduces consumeBufferedStreamEvent() and parseStreamEvent() to separate buffering and event parsing logic (handles "chunk", "done", "error").
Application of Results
clients/web/apps/dashboard/src/composables/useChat.ts
Adds applyStreamLineResult() to route parsed results to callbacks or raise errors.
Reader Pipeline
clients/web/apps/dashboard/src/composables/useChat.ts
Refactors readStreamEvents() and streamMessage() to use the modular pipeline and to capture the final done-event via callback.

Release Tooling, Tests & Docker

Layer / File(s) Summary
Execution Helpers & Parsing
scripts/release-contract.test.mjs
Adds readTomlSection() to extract TOML sections, and centralizes trusted executable directories via trustedExecutableDirectoryPaths/trustedExecutableDirs().
Test Harness Invocation
scripts/release-contract.test.mjs
Changes child-process invocation to use process.execPath and injects PATH from trusted directories; adds runners (runReleaseTagResolver, runReleaseContextResolver, runAffectedComponentsValidator).
Contract Tests
scripts/release-contract.test.mjs
Uses readTomlSection() to extract [package] stanza for version assertions; hardens cargo metadata error handling.
Transitive Expansion
scripts/resolve-release-components.mjs
Refactors expandTransitiveComponents() with helpers ensureReasonBucket() and addTransitiveComponent() to compute transitive affected components with reason tracking.
Release-tag Parsing Caution
scripts/resolve-release-from-tag.mjs
Changes parseAffectedComponentsOverride() to return a single matched string instead of an array — this alters the returned type and may break consumers expecting string[].
Docker builder tweak
clients/rook/Dockerfile
Adds --no-install-recommends and pins versions for certain packages during apt install in the builder stage.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Web Client
    participant Gateway as Agent Gateway
    participant Dispatcher as Webhook Dispatcher
    participant SSE as SSE Stream

    Client->>Gateway: POST /chat/stream
    activate Gateway

    alt Dispatcher Enabled
        Gateway->>Gateway: Build StreamDispatcherRequest
        Gateway->>Dispatcher: execute_stream_dispatcher()
        activate Dispatcher
        Dispatcher->>Dispatcher: Run webhook dispatch logic
        Dispatcher-->>Gateway: WebhookTurnResult
        deactivate Dispatcher
        Gateway->>Gateway: Map to StreamProcessingOutcome
    else Dispatcher Disabled
        Gateway->>Gateway: Legacy HTTP ingress handling
    end

    Gateway->>SSE: Emit SSE events (chunk/done/error)
    SSE-->>Client: Stream events
    Gateway->>Gateway: Update session activity
    deactivate Gateway
Loading
sequenceDiagram
    participant App as useChat.ts
    participant Reader as readStreamEvents
    participant Decoder as TextDecoder
    participant Parser as parseStreamEvent
    participant Callback as handleChunk/handleDone

    App->>Reader: readStreamEvents(stream, callbacks)
    activate Reader
    loop for each incoming chunk
        Reader->>Decoder: decode chunk
        Decoder-->>Reader: text
        Reader->>Reader: consumeStreamLine() → consumeBufferedStreamEvent()
        activate Parser
        Parser->>Parser: parseStreamEvent (chunk/done/error)
        Parser-->>Reader: StreamLineResult
        deactivate Parser
        Reader->>Reader: applyStreamLineResult(result, callbacks)
        Reader->>Callback: invoke onChunk or store doneEvent
    end
    Reader-->>App: StreamReadResult (captures doneEvent)
    deactivate Reader
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • dallay/corvus#769: Refactors streaming chat handling in clients/web/apps/dashboard/src/composables/useChat.ts with overlapping parsing pipeline changes.
  • dallay/corvus#784: Refactors webhook dispatcher execution/result mapping; affects the gateway dispatch path this PR delegates to.
  • dallay/corvus#732: Related test changes for Dream lock contention—both PRs address transient Busy handling in memory tests.

Suggested labels

risk:high

Suggested reviewers

  • yuniel-acosta
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% 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 follows Conventional Commit style with 'fix:' prefix and clearly describes the PR purpose—addressing SonarCloud quality gate issues. It is 43 characters, well under the 72-character limit.
Description check ✅ Passed The PR description covers all required template sections: Related Issues (with SonarCloud link), Summary (explaining fixes and refactors), Tested Information (comprehensive testing details with review guidance), Documentation Impact (clear explanation of no-docs rationale), Breaking Changes (none noted), and completed Checklist.
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.

✏️ 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 fix/sonarcloud-quality-gate-cleanup

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added the size/l Denotes a large change size label May 6, 2026
);
}

let content = std::fs::read_to_string(&canonical_skill_md_path)?;
Copy link
Copy Markdown

@semgrep-code-dallay semgrep-code-dallay Bot May 6, 2026

Choose a reason for hiding this comment

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

The application builds a file path from potentially untrusted data, which can lead to a path traversal vulnerability. An attacker can manipulate the path which the application uses to access files. If the application does not validate user input and sanitize file paths, sensitive files such as configuration or user data can be accessed, potentially creating or overwriting files. To prevent this vulnerability, validate and sanitize any input that is used to create references to file paths. Also, enforce strict file access controls. For example, choose privileges allowing public-facing applications to access only the required files.

🥳 Fixed in commit 0a966cb 🥳

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

/fp validate_and_parse_skill_md canonicalizes the resolved SKILL.md path, verifies the canonical path remains under the canonical skill directory, and only then reads/parses it. That boundary check covers .. traversal and symlink escapes before filesystem access.


std::fs::create_dir_all(dest)?;
for entry in std::fs::read_dir(src)? {
for entry in std::fs::read_dir(canonical_src)? {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Semgrep identified a blocking 🔴 issue in your code:
The application builds a file path from potentially untrusted data, which can lead to a path traversal vulnerability. An attacker can manipulate the path which the application uses to access files. If the application does not validate user input and sanitize file paths, sensitive files such as configuration or user data can be accessed, potentially creating or overwriting files. To prevent this vulnerability, validate and sanitize any input that is used to create references to file paths. Also, enforce strict file access controls. For example, choose privileges allowing public-facing applications to access only the required files.

Why this might be safe to ignore:

The code canonicalizes the path before use and explicitly validates that the canonicalized path stays within the canonical_root boundary, refusing to proceed if it escapes, which prevents path traversal attacks.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>clients/agent-runtime/src/skills/mod.rs</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/dallay/corvus/blob/de98462584c8eb3e26e7f47bf3adb4d561ce219a/clients/agent-runtime/src/skills/mod.rs#L468 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 468] canonical_src</a>"]
        end
        %% Intermediate

        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/dallay/corvus/blob/de98462584c8eb3e26e7f47bf3adb4d561ce219a/clients/agent-runtime/src/skills/mod.rs#L468 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 468] canonical_src</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    File0:::invis

    %% Connections

    Source --> Sink


Loading

To resolve this comment:

🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by tainted-path.

You can view more details about this finding in the Semgrep AppSec Platform.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

/fp copy_dir_recursive_checked validates both the canonical source directory and each canonical entry against the canonical source root before copying. Escaping symlinks/path traversal bail out before copy; latest patch also copies through staging so failed validation does not leave a partial destination.

);
}

let content = std::fs::read_to_string(&canonical_path)?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Semgrep identified a blocking 🔴 issue in your code:
The application builds a file path from potentially untrusted data, which can lead to a path traversal vulnerability. An attacker can manipulate the path which the application uses to access files. If the application does not validate user input and sanitize file paths, sensitive files such as configuration or user data can be accessed, potentially creating or overwriting files. To prevent this vulnerability, validate and sanitize any input that is used to create references to file paths. Also, enforce strict file access controls. For example, choose privileges allowing public-facing applications to access only the required files.

Why this might be safe to ignore:

The path is canonicalized before use and validated to ensure it stays within the canonical_skill_dir boundary, preventing path traversal. The input comes from local filesystem directory entries during skill loading, not from untrusted user input.

Dataflow graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>clients/agent-runtime/src/skills/mod.rs</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/dallay/corvus/blob/de98462584c8eb3e26e7f47bf3adb4d561ce219a/clients/agent-runtime/src/skills/mod.rs#L287 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 287] path</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/dallay/corvus/blob/de98462584c8eb3e26e7f47bf3adb4d561ce219a/clients/agent-runtime/src/skills/mod.rs#L287 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 287] canonical_path</a>"]
        end
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/dallay/corvus/blob/de98462584c8eb3e26e7f47bf3adb4d561ce219a/clients/agent-runtime/src/skills/mod.rs#L296 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 296] &canonical_path</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink


Loading

To resolve this comment:

🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by tainted-path.

You can view more details about this finding in the Semgrep AppSec Platform.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

/fp load_skill_md canonicalizes dir and path, checks canonical_path.starts_with(canonical_skill_dir), then reads from the canonicalized path. That prevents traversal/symlink escape outside the skill directory before the read occurs.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 6, 2026

Deploying corvus with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6fab139
Status: ✅  Deploy successful!
Preview URL: https://e6d0424b.corvus-42x.pages.dev
Branch Preview URL: https://fix-sonarcloud-quality-gate-j6ik.corvus-42x.pages.dev

View logs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
clients/rook/Dockerfile (1)

7-11: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pin apt package versions in builder stage for reproducible builds

Lines 7–11 install build dependencies without version pinning. While the final release image uses distroless (which excludes these packages), the builder stage has unpinned versions, creating supply-chain drift across builds. This is inconsistent with the pinned base images (rust:1.95, busybox:1.36.1, distroless/cc-debian13:nonroot). Keep --no-install-recommends and add version pins to clang, libclang-dev, and pkg-config for deterministic builds.

Suggested change
 RUN apt-get update && apt-get install -y --no-install-recommends \
-    clang \
-    libclang-dev \
-    pkg-config \
+    clang=<version> \
+    libclang-dev=<version> \
+    pkg-config=<version> \
     && rm -rf /var/lib/apt/lists/*
🤖 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 `@clients/rook/Dockerfile` around lines 7 - 11, The RUN that installs build
deps (clang, libclang-dev, pkg-config) in the builder stage must pin package
versions for reproducible builds; update the RUN in the builder stage that
contains "apt-get update && apt-get install -y --no-install-recommends \ clang \
libclang-dev \ pkg-config" to specify explicit version pins (e.g.
clang=<version>, libclang-dev=<version>, pkg-config=<version>) matching the
Debian base used, keep --no-install-recommends and the apt-get update, and
ensure the rm -rf /var/lib/apt/lists/* cleanup remains; use the same unique
package names (clang, libclang-dev, pkg-config) in the pins so the change is
easy to locate.
clients/agent-runtime/src/skills/mod.rs (2)

1031-1077: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Heads-up: canonicalize on broken symlinks aborts the whole install.

If skill_dir happens to be (or contain) a dangling symlink, skill_dir.canonicalize()? at Line 1034 / skill_md_path.canonicalize()? at Line 1045 returns Err, and the function bubbles up before the remove_dir_all cleanup branches run — so a half-installed skill directory can be left on disk. Consider mapping these errors to a cleanup-then-bail path so failure modes converge with the other validation branches in this function.

🤖 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 `@clients/agent-runtime/src/skills/mod.rs` around lines 1031 - 1077, The
canonicalize calls in validate_and_parse_skill_md (on skill_dir and on
skill_md_path) can fail for dangling symlinks and currently propagate the error
before remove_dir_all runs; change both usages to explicitly handle Err by
attempting std::fs::remove_dir_all(skill_dir) and then returning an
anyhow::Error (i.e., replace the `...?` with a match or map_err closure that
calls remove_dir_all and then anyhow::bail! / Err(anyhow::Error::msg(...)) with
a clear message including the original error), so all failure paths perform the
same cleanup before bailing.

454-488: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Symlinks are still silently dereferenced — and a symlink loop inside the source root will recurse forever.

The "escape" check uses canonicalize, so a symlink that resolves inside canonical_root passes the guard. Two consequences:

  1. Silent deref: internal symlinks are followed and the target's contents are copied as a regular file/dir. Skill layouts that intentionally contain symlinks lose that semantic at install time — and the copy can pull in significantly more data than the user expects.
  2. Loop hazard: a self-referential symlink that resolves to an ancestor still inside canonical_root (e.g. src/loop -> src) will pass starts_with(canonical_root) and trigger unbounded recursion via read_dircanonicalizecopy_dir_recursive_checked → … with create_dir_all/std::fs::copy happily overwriting on each pass. The new copy_dir_recursive_rejects_symlink_escape test only covers the escape case, not the loop case.

Detecting symlinks via entry.file_type() (or symlink_metadata) and refusing/skipping them before any canonicalize call closes both holes and is also one fewer syscall per entry.

🛡️ Suggested guard
     for entry in std::fs::read_dir(canonical_src)? {
         let entry = entry?;
+        let file_type = entry.file_type()?;
+        if file_type.is_symlink() {
+            anyhow::bail!(
+                "Refusing to copy skill entry '{}' because it is a symlink",
+                entry.path().display(),
+            );
+        }
         let src_path = entry.path();
         let canonical_entry_path = src_path.canonicalize()?;

A regression test with src/loop -> src (or src/loop -> .) would lock this in.

🤖 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 `@clients/agent-runtime/src/skills/mod.rs` around lines 454 - 488, The
copy_dir_recursive_checked function currently canonicalizes every entry which
silently dereferences symlinks and allows symlink loops; change the logic to
call entry.file_type() or std::fs::symlink_metadata on each DirEntry (before any
canonicalize) to detect symlinks and either refuse or skip them (update behavior
consistently), only call canonicalize for non-symlink entries, and then proceed
with the existing starts_with and recursion/copy; also add a regression test
that creates a self-referential symlink (e.g., src/loop -> src or -> .) to
ensure loops are rejected/skipped and do not recurse forever.
🤖 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 `@clients/agent-runtime/src/gateway/mod.rs`:
- Around line 2499-2543: execute_stream_dispatcher is requesting SSE frames
(include_sse_frames: true) but stream_outcome_from_dispatch_result ignores
result.event_frames, causing needless buffering; either stop requesting frames
or propagate them: change execute_stream_dispatcher (include_sse_frames) to
false if the stream contract only needs final text, or update
stream_outcome_from_dispatch_result and the StreamProcessingOutcome type to
accept and prefer result.event_frames (thread event_frames through
StreamProcessingOutcome and emit those instead of falling back to
response_text), adjusting callers of StreamProcessingOutcome accordingly.

In `@clients/agent-runtime/src/skills/mod.rs`:
- Around line 2132-2149: Add a sibling unit test that ensures copy_dir_recursive
(and by extension copy_dir_recursive_checked) rejects symlink loops: create a
temp src dir with a marker file, create a symlink inside src that points back to
src (or to "."), call copy_dir_recursive(src.path(), &dst.path().join("copy")),
assert the call returns an Err (or does not hang) and assert that dst does not
contain duplicated or escaped entries from the loop (e.g., dst/.../marker file
should not exist or should not be recursively copied); name the test something
like copy_dir_recursive_rejects_symlink_loop and mirror the style of the
existing copy_dir_recursive_rejects_symlink_escape test.

In `@clients/web/apps/dashboard/src/composables/useChat.ts`:
- Around line 270-297: readStreamEvents currently returns void and relies on the
onDone callback to stash the final StreamDoneEvent into a StreamReadResult
wrapper; change readStreamEvents to return the captured StreamDoneEvent (or null
if none) directly by updating its signature from Promise<void> to
Promise<StreamDoneEvent | null>, collect the final doneEvent inside the
loop/after-buffer processing and return it instead of only calling onDone, and
then remove the mutable wrapper usage at call sites and fold any session-update
side-effect into a small caller helper that applies the returned doneEvent and
updates session state; refer to readStreamEvents, StreamDoneEvent, processLine,
and onDone to locate where to capture and return the final event.
- Around line 683-696: The read flow currently can exit early or throw from
readStreamEvents without releasing the ReadableStreamDefaultReader, so update
the logic around reader and readStreamEvents (the reader used by
readStreamEvents, the streamReadResult / handleDoneEvent callback, and post-read
handling that throws fallbackMessage) to always tear down the reader: wrap the
await readStreamEvents(...) and the subsequent doneEvent check in a try/finally
(or catch then finally) where in the finally you call reader.cancel() (or at
minimum reader.releaseLock()) to ensure the stream is cancelled/released when
readStreamEvents throws or when doneEvent is missing; keep setSessionReady usage
unchanged inside handleDoneEvent.

In `@scripts/release-contract.test.mjs`:
- Around line 24-33: readTomlSection currently looks for a section header
followed by a literal "\n", which breaks on CRLF checkouts; update
readTomlSection to be newline-agnostic by locating the sectionHeader
(`[${sectionName}]`) regardless of whether it's followed by "\n" or "\r\n",
compute bodyStart after the matched newline sequence, and find nextSectionStart
by searching for the next section marker that also tolerates CRLF vs LF (e.g.,
look for "\n[" or "\r\n[" or use a regex with \r?\n\[) so the returned slice of
the section body is correct on both Windows and Unix.

In `@scripts/resolve-release-components.mjs`:
- Around line 87-105: The loop in expandTransitiveComponents uses Array.some
which short-circuits and only records the first satisfied dependsOnReleaseOf
reason; replace the .some-based logic with explicit iteration so every
dependency for each component is evaluated: in expandTransitiveComponents
iterate over Object.entries(graph.components) and then for each component
iterate all component.dependsOnReleaseOf (for...of or forEach) and call
addTransitiveComponent for each dependency, updating the changed flag with
logical OR when any call returns true so all transitive reasons (added by
ensureReasonBucket/reasons push inside addTransitiveComponent) are preserved.

---

Outside diff comments:
In `@clients/agent-runtime/src/skills/mod.rs`:
- Around line 1031-1077: The canonicalize calls in validate_and_parse_skill_md
(on skill_dir and on skill_md_path) can fail for dangling symlinks and currently
propagate the error before remove_dir_all runs; change both usages to explicitly
handle Err by attempting std::fs::remove_dir_all(skill_dir) and then returning
an anyhow::Error (i.e., replace the `...?` with a match or map_err closure that
calls remove_dir_all and then anyhow::bail! / Err(anyhow::Error::msg(...)) with
a clear message including the original error), so all failure paths perform the
same cleanup before bailing.
- Around line 454-488: The copy_dir_recursive_checked function currently
canonicalizes every entry which silently dereferences symlinks and allows
symlink loops; change the logic to call entry.file_type() or
std::fs::symlink_metadata on each DirEntry (before any canonicalize) to detect
symlinks and either refuse or skip them (update behavior consistently), only
call canonicalize for non-symlink entries, and then proceed with the existing
starts_with and recursion/copy; also add a regression test that creates a
self-referential symlink (e.g., src/loop -> src or -> .) to ensure loops are
rejected/skipped and do not recurse forever.

In `@clients/rook/Dockerfile`:
- Around line 7-11: The RUN that installs build deps (clang, libclang-dev,
pkg-config) in the builder stage must pin package versions for reproducible
builds; update the RUN in the builder stage that contains "apt-get update &&
apt-get install -y --no-install-recommends \ clang \ libclang-dev \ pkg-config"
to specify explicit version pins (e.g. clang=<version>, libclang-dev=<version>,
pkg-config=<version>) matching the Debian base used, keep
--no-install-recommends and the apt-get update, and ensure the rm -rf
/var/lib/apt/lists/* cleanup remains; use the same unique package names (clang,
libclang-dev, pkg-config) in the pins so the change is easy to locate.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 059178c9-9e01-4b75-86e8-355008723b1d

📥 Commits

Reviewing files that changed from the base of the PR and between cfb9b3d and 2922d0c.

📒 Files selected for processing (8)
  • clients/agent-runtime/src/gateway/mod.rs
  • clients/agent-runtime/src/memory/dream.rs
  • clients/agent-runtime/src/skills/mod.rs
  • clients/rook/Dockerfile
  • clients/web/apps/dashboard/src/composables/useChat.ts
  • scripts/release-contract.test.mjs
  • scripts/resolve-release-components.mjs
  • scripts/resolve-release-from-tag.mjs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: sonar
  • GitHub Check: pr-checks
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (6)
**/*

⚙️ CodeRabbit configuration file

**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.

Files:

  • clients/rook/Dockerfile
  • clients/agent-runtime/src/memory/dream.rs
  • scripts/resolve-release-components.mjs
  • scripts/resolve-release-from-tag.mjs
  • scripts/release-contract.test.mjs
  • clients/agent-runtime/src/gateway/mod.rs
  • clients/agent-runtime/src/skills/mod.rs
  • clients/web/apps/dashboard/src/composables/useChat.ts
clients/agent-runtime/src/**/*.rs

📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)

clients/agent-runtime/src/**/*.rs: Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements
Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency

Files:

  • clients/agent-runtime/src/memory/dream.rs
  • clients/agent-runtime/src/gateway/mod.rs
  • clients/agent-runtime/src/skills/mod.rs
clients/agent-runtime/**/*.rs

📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)

Run cargo fmt --all -- --check, cargo clippy --all-targets -- -D warnings, and cargo test for code validation, or document which checks were skipped and why

Files:

  • clients/agent-runtime/src/memory/dream.rs
  • clients/agent-runtime/src/gateway/mod.rs
  • clients/agent-runtime/src/skills/mod.rs
**/*.rs

⚙️ CodeRabbit configuration file

**/*.rs: Focus on Rust idioms, memory safety, and ownership/borrowing correctness.
Flag unnecessary clones, unchecked panics in production paths, and weak error context.
Prioritize unsafe blocks, FFI boundaries, concurrency races, and secret handling.

Files:

  • clients/agent-runtime/src/memory/dream.rs
  • clients/agent-runtime/src/gateway/mod.rs
  • clients/agent-runtime/src/skills/mod.rs
clients/agent-runtime/src/{security,gateway,tools}/**/*.rs

📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)

Treat src/security/, src/gateway/, src/tools/ as high-risk surfaces and never broaden filesystem/network execution scope without explicit policy checks

Files:

  • clients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs

📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)

Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable

Files:

  • clients/agent-runtime/src/gateway/mod.rs
🪛 Hadolint (2.14.0)
clients/rook/Dockerfile

[warning] 7-7: Pin versions in apt get install. Instead of apt-get install <package> use apt-get install <package>=<version>

(DL3008)

🔇 Additional comments (2)
clients/agent-runtime/src/memory/dream.rs (1)

710-711: LGTM — retry wrapper + lock assertion are the right fix.

The replacement of a bare run_if_triggered(...).unwrap().unwrap() with run_if_triggered_after_transient_busy plus assert_eq!(first_report.lock_state, DreamLockState::Acquired) correctly guards against the test hitting transient busy state left by a parallel test runner and makes the expected post-condition explicit. No behavioral change to production code paths.

One heads-up on the helper: run_after_transient_busy caps retries at 10 × 10 ms = 100 ms. If the host is starved longer than that, the final last_report.expect(...) either panics (all None returns) or hands back a Busy report, which would cause the Acquired assertion here to fail loudly. That's the right failure mode — just worth knowing if this test becomes intermittently flaky on slow CI agents.

clients/agent-runtime/src/skills/mod.rs (1)

285-319: LGTM — and the canonicalized dir_name matches install_local_skill's naming.

canonical_skill_dir.file_name() resolves through the install-time symlink, but install_local_skill already derives the destination name from canonical_src.file_name() (Line 1269), so the two stay consistent and frontmatter-name validation still works as intended. Path-escape guard before read_to_string is the right ordering.

Comment thread clients/agent-runtime/src/gateway/mod.rs
Comment thread clients/agent-runtime/src/skills/mod.rs
Comment thread clients/web/apps/dashboard/src/composables/useChat.ts
Comment thread clients/web/apps/dashboard/src/composables/useChat.ts Outdated
Comment thread scripts/release-contract.test.mjs Outdated
Comment thread scripts/resolve-release-components.mjs Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
clients/web/apps/dashboard/src/composables/useChat.ts (1)

238-240: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle non-JSON SSE error payloads without failing parsing.

parseStreamEvent assumes error data is JSON, but backend SSE currently emits error_data.to_string() in clients/agent-runtime/src/gateway/mod.rs:2530-2558. A plain-text error will throw here and mask the real server message.

Suggested fix
   if (eventName === "error") {
-    const errorEvt = parseStreamEventJson<StreamErrorEvent>(eventData, fallbackMessage);
-    return { type: "error", message: errorEvt.message || fallbackMessage };
+    try {
+      const parsed = JSON.parse(eventData) as StreamErrorEvent | string;
+      if (typeof parsed === "string") {
+        return { type: "error", message: parsed.trim() || fallbackMessage };
+      }
+      return { type: "error", message: parsed.message?.trim() || fallbackMessage };
+    } catch {
+      return { type: "error", message: eventData.trim() || fallbackMessage };
+    }
   }
As per coding guidelines, "Look for behavioral regressions, missing tests, and contract breaks across modules."
🤖 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 `@clients/web/apps/dashboard/src/composables/useChat.ts` around lines 238 -
240, The error handler assumes SSE error payloads are JSON; change the logic in
the eventName === "error" branch (where
parseStreamEventJson<StreamErrorEvent>(eventData, fallbackMessage) is called) to
try JSON parsing but gracefully handle plain-text payloads: attempt to parse
eventData as JSON into StreamErrorEvent, and if parsing fails or yields no
message fall back to using the raw eventData string (or fallbackMessage) for the
returned message; ensure parseStreamEventJson usage is replaced or wrapped with
this safe-parse behavior so non-JSON SSE `error` emissions from the backend do
not throw and the real server message is preserved.
scripts/release-contract.test.mjs (1)

1167-1176: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

releaseVersion is not regex-escaped before use in new RegExp.

Line 1175 constructs new RegExp(^version = "${releaseVersion}"$, "m"). Semver strings like 1.2.3 contain . which is a metacharacter and matches any character — 1X2Y3 would also pass. Use String.raw escaping or a literal string comparison instead.

🛡️ Proposed fix
-  assert.match(packageStanza, new RegExp(`^version = "${releaseVersion}"$`, "m"));
+  const escapedVersion = releaseVersion.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+  assert.match(packageStanza, new RegExp(`^version = "${escapedVersion}"$`, "m"));
🤖 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 `@scripts/release-contract.test.mjs` around lines 1167 - 1176, The test uses
new RegExp(`^version = "${releaseVersion}"$`, "m") which treats dots in
releaseVersion as regex metacharacters; update the assertion to either escape
releaseVersion before constructing the RegExp or avoid RegExp entirely by
extracting the packageStanza value and doing a strict string or equality check
against `version = "<releaseVersion>"`; modify the test named "cargo publish
contract keeps local cerebro path and release version aligned" to use an escaped
releaseVersion (e.g. escapeRegExp(releaseVersion)) or compare packageStanza
lines literally instead of using new RegExp.
clients/rook/Dockerfile (1)

3-3: 🧹 Nitpick | 🔵 Trivial

Base images are not pinned by digest — supply chain risk.

rust:1.95-slim-trixie and gcr.io/distroless/cc-debian13:nonroot are mutable tags; a compromised or accidentally-retagged image would silently affect every build.

Pin by digest for the images you do not control (at minimum the release stage, which ships):

-FROM gcr.io/distroless/cc-debian13:nonroot AS release
+FROM gcr.io/distroless/cc-debian13:nonroot@sha256:<digest> AS release

Run docker buildx imagetools inspect gcr.io/distroless/cc-debian13:nonroot to get the current digest.

🤖 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 `@clients/rook/Dockerfile` at line 3, The Dockerfile uses mutable tags; replace
the unpinned bases with digest-pinned references: update the "FROM
rust:1.95-slim-trixie AS builder" line to use the rust image digest and update
the release stage "FROM gcr.io/distroless/cc-debian13:nonroot" to use its
`@sha256`:... digest. Obtain the exact digests with "docker buildx imagetools
inspect <image>:<tag>" (e.g., inspect rust:1.95-slim-trixie and
gcr.io/distroless/cc-debian13:nonroot) and then substitute the tags with the
returned `@sha256` digests so both the builder and release stages are pinned.
♻️ Duplicate comments (2)
scripts/resolve-release-components.mjs (1)

87-94: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Preserve all transitive reasons even after a component is already marked affected.

The current guard short-circuits once componentId is already in affectedComponents, so later satisfied dependencies never get recorded in reasons.

Suggested fix
 function addTransitiveComponent(affectedComponents, reasons, componentId, dependency) {
-  if (!affectedComponents.has(dependency) || affectedComponents.has(componentId)) {
+  if (!affectedComponents.has(dependency)) {
     return false;
   }
 
-  affectedComponents.add(componentId);
-  ensureReasonBucket(reasons, componentId).push(`depends-on-release-of:${dependency}`);
-  return true;
+  const bucket = ensureReasonBucket(reasons, componentId);
+  const reason = `depends-on-release-of:${dependency}`;
+  if (!bucket.includes(reason)) {
+    bucket.push(reason);
+  }
+
+  if (affectedComponents.has(componentId)) {
+    return false;
+  }
+
+  affectedComponents.add(componentId);
+  return true;
 }
As per coding guidelines, "Look for behavioral regressions, missing tests, and contract breaks across modules."

Also applies to: 104-107

🤖 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 `@scripts/resolve-release-components.mjs` around lines 87 - 94, The current
addTransitiveComponent function returns early when componentId is already in
affectedComponents, which prevents recording additional transitive reasons;
change the logic so you always call ensureReasonBucket(reasons,
componentId).push(...) to record the new `depends-on-release-of:${dependency}`
reason even if affectedComponents already contains componentId, and only add to
affectedComponents when it wasn't present; apply the same fix to the other
identical guard further down the file where ensureReasonBucket is used.
clients/web/apps/dashboard/src/composables/useChat.ts (1)

689-700: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Cancel the stream reader on teardown, not only release the lock.

reader.releaseLock() alone does not terminate an in-flight body when parsing throws mid-stream. Cancel first to avoid dangling network reads on error paths.

Suggested fix
       } finally {
+        await reader.cancel().catch(() => {});
         reader.releaseLock();
       }
As per coding guidelines, "Security first, performance second."
🤖 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 `@clients/web/apps/dashboard/src/composables/useChat.ts` around lines 689 -
700, The teardown currently only calls reader.releaseLock(), which doesn’t
cancel an in-flight stream and can leave network reads dangling; update the
finally block in the function surrounding readStreamEvents so you call
reader.cancel() (or await reader.cancel() if appropriate) before calling
reader.releaseLock(), ensuring any in-flight parsing errors trigger stream
cancellation; reference the reader variable and the
readStreamEvents/applyStreamDoneEvent flow to locate the try/finally around the
stream handling and add the cancel step there.
🤖 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 `@clients/agent-runtime/src/gateway/mod.rs`:
- Around line 2524-2527: The terminal webhook log call in
log_webhook_terminal_outcome uses runtime_path="stream_dispatcher" which is
inconsistent with the earlier log_webhook_runtime_path() value
("dispatcher_agent"); update the log_webhook_terminal_outcome invocation so it
uses the same runtime_path used by log_webhook_runtime_path (e.g.,
"dispatcher_agent") to keep labels consistent for the same request (reference
symbols: log_webhook_terminal_outcome, log_webhook_runtime_path,
webhook_outcome_label, request.session_id, result.outcome).

In `@clients/agent-runtime/src/skills/mod.rs`:
- Around line 449-452: The copy_dir_recursive function must detect and reject
when the destination is inside the source tree to avoid infinite recursion:
first canonicalize dest (like canonical_src) and check whether
canonical_dest.starts_with(&canonical_src) (or otherwise is an
ancestor/descendant) and return an Err before calling
copy_dir_recursive_checked; mention the symbols to change: copy_dir_recursive,
src, dest, canonical_src, and call to copy_dir_recursive_checked so the check
happens prior to traversal and directory creation.

In `@clients/rook/Dockerfile`:
- Around line 8-10: The Dockerfile currently pins clang=1:19.0-63,
libclang-dev=1:19.0-63 and pkg-config=1.8.1-4 which will break when
trixie-security/trixie-updates publishes patch releases; update the Dockerfile
to use flexible constraints (replace the pinned package entries clang,
libclang-dev, pkg-config) or, if exact pins are required, add a RUN apt-cache
policy clang libclang-dev pkg-config step in your CI/Docker build to log
available versions so version drift is visible (target the package names shown:
clang, libclang-dev, pkg-config).

In `@scripts/release-contract.test.mjs`:
- Around line 24-35: The RegExp in readTomlSection interpolates sectionName
directly, so names with regex metacharacters break the pattern; fix by escaping
sectionName before building the RegExp (add an escape utility or inline replace
that escapes characters like . * + ? ^ $ { } ( ) | [ ] \ ) and then use the
escaped string in the existing new RegExp(`^\\[${escapedSectionName}\\]\\r?\\n`,
"m") call so the function safely handles arbitrary section names.
- Around line 128-137: trustedExecutableDirs() is a trivial wrapper that just
returns trustedExecutableDirectoryPaths; remove the unnecessary indirection by
deleting the trustedExecutableDirs() function and replace all call sites that
use trustedExecutableDirs() with the constant trustedExecutableDirectoryPaths so
callers reference the array directly.

---

Outside diff comments:
In `@clients/rook/Dockerfile`:
- Line 3: The Dockerfile uses mutable tags; replace the unpinned bases with
digest-pinned references: update the "FROM rust:1.95-slim-trixie AS builder"
line to use the rust image digest and update the release stage "FROM
gcr.io/distroless/cc-debian13:nonroot" to use its `@sha256`:... digest. Obtain the
exact digests with "docker buildx imagetools inspect <image>:<tag>" (e.g.,
inspect rust:1.95-slim-trixie and gcr.io/distroless/cc-debian13:nonroot) and
then substitute the tags with the returned `@sha256` digests so both the builder
and release stages are pinned.

In `@clients/web/apps/dashboard/src/composables/useChat.ts`:
- Around line 238-240: The error handler assumes SSE error payloads are JSON;
change the logic in the eventName === "error" branch (where
parseStreamEventJson<StreamErrorEvent>(eventData, fallbackMessage) is called) to
try JSON parsing but gracefully handle plain-text payloads: attempt to parse
eventData as JSON into StreamErrorEvent, and if parsing fails or yields no
message fall back to using the raw eventData string (or fallbackMessage) for the
returned message; ensure parseStreamEventJson usage is replaced or wrapped with
this safe-parse behavior so non-JSON SSE `error` emissions from the backend do
not throw and the real server message is preserved.

In `@scripts/release-contract.test.mjs`:
- Around line 1167-1176: The test uses new RegExp(`^version =
"${releaseVersion}"$`, "m") which treats dots in releaseVersion as regex
metacharacters; update the assertion to either escape releaseVersion before
constructing the RegExp or avoid RegExp entirely by extracting the packageStanza
value and doing a strict string or equality check against `version =
"<releaseVersion>"`; modify the test named "cargo publish contract keeps local
cerebro path and release version aligned" to use an escaped releaseVersion (e.g.
escapeRegExp(releaseVersion)) or compare packageStanza lines literally instead
of using new RegExp.

---

Duplicate comments:
In `@clients/web/apps/dashboard/src/composables/useChat.ts`:
- Around line 689-700: The teardown currently only calls reader.releaseLock(),
which doesn’t cancel an in-flight stream and can leave network reads dangling;
update the finally block in the function surrounding readStreamEvents so you
call reader.cancel() (or await reader.cancel() if appropriate) before calling
reader.releaseLock(), ensuring any in-flight parsing errors trigger stream
cancellation; reference the reader variable and the
readStreamEvents/applyStreamDoneEvent flow to locate the try/finally around the
stream handling and add the cancel step there.

In `@scripts/resolve-release-components.mjs`:
- Around line 87-94: The current addTransitiveComponent function returns early
when componentId is already in affectedComponents, which prevents recording
additional transitive reasons; change the logic so you always call
ensureReasonBucket(reasons, componentId).push(...) to record the new
`depends-on-release-of:${dependency}` reason even if affectedComponents already
contains componentId, and only add to affectedComponents when it wasn't present;
apply the same fix to the other identical guard further down the file where
ensureReasonBucket is used.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 55fc7455-4c3e-491e-a1fa-f1cc8c5830cb

📥 Commits

Reviewing files that changed from the base of the PR and between 2922d0c and 0a966cb.

📒 Files selected for processing (6)
  • clients/agent-runtime/src/gateway/mod.rs
  • clients/agent-runtime/src/skills/mod.rs
  • clients/rook/Dockerfile
  • clients/web/apps/dashboard/src/composables/useChat.ts
  • scripts/release-contract.test.mjs
  • scripts/resolve-release-components.mjs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: pr-checks
  • GitHub Check: sonar
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (6)
**/*

⚙️ CodeRabbit configuration file

**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.

Files:

  • scripts/resolve-release-components.mjs
  • clients/rook/Dockerfile
  • clients/web/apps/dashboard/src/composables/useChat.ts
  • clients/agent-runtime/src/skills/mod.rs
  • clients/agent-runtime/src/gateway/mod.rs
  • scripts/release-contract.test.mjs
clients/agent-runtime/src/**/*.rs

📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)

clients/agent-runtime/src/**/*.rs: Never log secrets, tokens, raw credentials, or sensitive payloads in any logging statements
Avoid unnecessary allocations, clones, and blocking operations to maintain performance and efficiency

Files:

  • clients/agent-runtime/src/skills/mod.rs
  • clients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/**/*.rs

📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)

Run cargo fmt --all -- --check, cargo clippy --all-targets -- -D warnings, and cargo test for code validation, or document which checks were skipped and why

Files:

  • clients/agent-runtime/src/skills/mod.rs
  • clients/agent-runtime/src/gateway/mod.rs
**/*.rs

⚙️ CodeRabbit configuration file

**/*.rs: Focus on Rust idioms, memory safety, and ownership/borrowing correctness.
Flag unnecessary clones, unchecked panics in production paths, and weak error context.
Prioritize unsafe blocks, FFI boundaries, concurrency races, and secret handling.

Files:

  • clients/agent-runtime/src/skills/mod.rs
  • clients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/{security,gateway,tools}/**/*.rs

📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)

Treat src/security/, src/gateway/, src/tools/ as high-risk surfaces and never broaden filesystem/network execution scope without explicit policy checks

Files:

  • clients/agent-runtime/src/gateway/mod.rs
clients/agent-runtime/src/{security,gateway,tools,config}/**/*.rs

📄 CodeRabbit inference engine (clients/agent-runtime/AGENTS.md)

Do not silently weaken security policy or access constraints; keep default behavior secure-by-default with deny-by-default where applicable

Files:

  • clients/agent-runtime/src/gateway/mod.rs
🔇 Additional comments (6)
scripts/release-contract.test.mjs (3)

53-66: LGTM — process.execPath + trusted PATH propagation is the right hardening.

Switching all child-process helpers from the string "node" to process.execPath and replacing an inherited, potentially attacker-influenced PATH with trustedExecutableDirectoryPaths.join(path.delimiter) is a clean, effective fix for the SonarCloud security hotspot. No concerns.

Also applies to: 68-78, 92-102, 660-673, 675-691, 784-796


24-35: Past review comment is resolved.

The CRLF-agnostic rewrite of readTomlSection using \r?\n in both the section-header regex and the next-section search correctly handles both LF and CRLF checkouts. The previous brittle indexOf("\n[") approach is gone.


1197-1208: Cargo stderr normalization is correct.

Buffer → string → empty-string fallback chain handles all known execFileSync error shapes cleanly. The network-access skip guard is a sensible CI adaptation.

clients/rook/Dockerfile (1)

7-7: --no-install-recommends is the right call.

Reduces the builder-layer attack surface by excluding optional packages. LGTM.

clients/agent-runtime/src/skills/mod.rs (2)

286-315: Nice path-confinement hardening.

Canonicalizing both the skill directory and SKILL.md before reading closes symlink and traversal escapes, and anchoring location to the canonical manifest path keeps later checks pointed at the real file.

Also applies to: 1057-1097


958-972: Good atomic-copy coverage.

The staging-dir cleanup in copy_dir_atomic, plus the new loop/escape tests, materially reduces the chance of leaving half-copied skill contents behind on failure.

Also applies to: 2173-2231

Comment thread clients/agent-runtime/src/gateway/mod.rs
Comment thread clients/agent-runtime/src/skills/mod.rs
Comment thread clients/rook/Dockerfile Outdated
Comment thread scripts/release-contract.test.mjs
Comment thread scripts/release-contract.test.mjs Outdated
yacosta738 added 2 commits May 6, 2026 13:07
- gateway: use consistent runtime_path label 'dispatcher_agent' in terminal outcome log
- skills: add dest-inside-src check before copying, handle non-existent dest gracefully
- rook: pin base images by digest, use flexible package version constraints
- dashboard: handle plain-text SSE error payloads gracefully, add reader.cancel() before releaseLock()
- release-contract: escape regex metacharacters in TOML section parsing and version matching
- release-contract: remove unnecessary trustedExecutableDirs wrapper, use constant directly
- resolve-release-components: always record transitive dependency reasons even when component already in set
- dashboard: add test for plain-text SSE error fallback in stream parsing
- release-contract: add test verifying multiple transitive reasons are recorded
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 6, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
78.2% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@yacosta738 yacosta738 merged commit fd854d0 into main May 6, 2026
15 of 18 checks passed
@yacosta738 yacosta738 deleted the fix/sonarcloud-quality-gate-cleanup branch May 6, 2026 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:high size/l Denotes a large change size

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant