Skip to content

Wave 4: runtime-host - #5

Merged
ThePlenkov merged 3 commits into
wave-3-runtimefrom
wave-4-runtime-host
Aug 11, 2026
Merged

ThePlenkov merged 3 commits into
wave-3-runtimefrom
wave-4-runtime-host

Conversation

@ThePlenkov

@ThePlenkov ThePlenkov commented Aug 9, 2026 •

Copy link
Copy Markdown
Contributor

User description

Summary

  • HostExecutor implementation: allowlist enforcement, env/credential passing, artifact collection, log truncation, timeout + SIGKILL grace
  • 47 tests pass across 4 files (allowlist, errors, host-executor, public-api)
  • Typecheck clean, build produces dist/index.mjs + dist/index.d.mts
  • Spec 05 amended to match built runtime contract (request.env/request.credentials, retry is scheduler-owned)
  • Reviewer approved (sv-gab)

Test plan

  • bun run test (runtime-host: 47 tests pass)
  • bun run typecheck (clean)
  • bun run build (green)
  • reviewer approved

Stacked on #3

Generated with Devin


CodeAnt-AI Description

Add a controlled host executor for running approved local commands

What Changed

  • Adds a public host executor that runs allowlisted local commands and reports status, exit codes, logs, duration, and collected artifacts
  • Restricts environment variables, working directories, and privilege-related commands to reduce unintended access
  • Stops processes that exceed their timeout, limits oversized logs, and reports missing artifacts without hiding the command result
  • Exposes the executor, allowlist, configuration types, and structured errors through the package API
  • Adds coverage for command filtering, execution outcomes, timeouts, environment handling, workspace boundaries, artifacts, log limits, and security checks

Impact

✅ Controlled local command execution
✅ Fewer stuck processes and oversized logs
✅ Reduced environment leakage and workspace escapes

🔄 Retrigger CodeAnt AI Review

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ThePlenkov, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6f17ce5a-b1a4-47f7-9a74-75dfd1602510

📥 Commits

Reviewing files that changed from the base of the PR and between 34f1f80 and 5908184.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • package.json
  • packages/core/src/internal/plan.ts
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added host-process command execution with configurable command and environment allowlists.
    • Added timeout handling, output capture and truncation, artifact collection, workspace validation, and structured execution errors.
    • Added safeguards against root, sudo, and su execution.
    • Workspace, artifacts, environment, and credentials are now scoped per execution request.
  • Documentation

    • Added an implementation plan and updated host executor specifications, including scheduler-managed retries.
  • Chores

    • Updated package entry points and modernized lint commands.
    • Pinned development dependency versions.

Walkthrough

The pull request adds the HostExecutor runtime implementation, its public contracts, validation, process handling, artifact collection, and tests. It also moves execution paths to request scope, updates package entrypoints, removes deprecated ESLint options, and pins development dependencies.

Changes

Runtime host execution

Layer / File(s) Summary
Host executor contracts and security rules
engdocs/architecture/wave-04-runtime-host-plan.md, packages/runtime-host/src/allowlist.ts, packages/runtime-host/src/config.ts, packages/runtime-host/src/errors.ts, specs/05-runtime-host/spec.md, packages/runtime-host/src/__tests__/allowlist.test.ts, packages/runtime-host/src/__tests__/errors.test.ts
Defines HostExecutorConfig, command allowlisting, typed errors, request-scoped paths and environment values, scheduler-owned retries, and privilege validation without setuid.
Host process execution and result handling
packages/runtime-host/src/host-executor.ts, packages/runtime-host/src/__tests__/host-executor.test.ts, packages/runtime-host/src/__tests__/helpers/fixtures.ts
Adds command execution, restricted environments, workspace-safe directories, timeout termination, output capture, log truncation, artifact copying, and failure results.
Public package surface and request-scoped behavior
packages/runtime-host/src/index.ts, packages/runtime-host/package.json, packages/runtime-host/src/__tests__/public-api.test.ts, specs/05-runtime-host/spec.md
Exports the runtime-host API, updates ESM entrypoints and workspace dependencies, and documents request-scoped execution behavior.
Workspace tooling alignment
package.json, packages/*/package.json, packages/runtime-docker/package.json, packages/core/src/internal/plan.ts
Pins development dependencies, removes deprecated ESLint extension flags, updates runtime-docker metadata, and reorders type-only imports.

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

Sequence Diagram(s)

sequenceDiagram
  participant ExecuteRequest
  participant HostExecutor
  participant ChildProcess
  participant ArtifactDirectory
  ExecuteRequest->>HostExecutor: execute(request)
  HostExecutor->>ChildProcess: spawn command with request workspace and environment
  ChildProcess-->>HostExecutor: logs and exit status
  HostExecutor->>ArtifactDirectory: copy declared artifacts
  ArtifactDirectory-->>HostExecutor: paths or copy errors
  HostExecutor-->>ExecuteRequest: execution result
Loading

Possibly related PRs

🚥 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.
Title check ✅ Passed The title clearly identifies the main runtime-host package change and is concise.
Description check ✅ Passed The description directly explains the HostExecutor implementation, security controls, tests, build results, and specification updates.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wave-4-runtime-host

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

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Wave 4: Add runtime-host HostExecutor with allowlist, env passing, timeout, and artifacts

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Implement a host-process Executor with allowlist enforcement, bounded env/credential passing, and
 cwd constraints.
• Add timeout handling (SIGTERM + SIGKILL grace), log truncation, and artifact collection into
 request.artifactDir.
• Add comprehensive vitest coverage and align Spec 05 + package outputs to the built runtime
 contract.
Diagram

graph TD
  SVC_RT["@sverka/runtime (Scheduler)"] --> SVC_HE["HostExecutor"] --> SVC_AL["CommandAllowlist"]
  SVC_HE --> PROC_CP["Child process"] --> FS_WS[("Workspace")]
  SVC_HE --> FS_AD[("Artifact dir")]
  SVC_HE --> PROC_CP
  subgraph Legend
    direction LR
    _svc[Service] ~~~ _proc[Process] ~~~ _fs[(Filesystem)]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use a process-exec library (e.g., execa)
  • ➕ Simplifies spawn/output collection/timeout handling and edge cases across platforms
  • ➕ Often provides better ergonomics for buffering, maxBuffer, and signal handling
  • ➖ Adds a dependency and potential ESM/CJS friction in this workspace
  • ➖ May reduce transparency/control over exact timeout + SIGKILL grace semantics required by the spec
2. Truncate by bytes (Buffer) rather than JS string length
  • ➕ More accurate enforcement of maxLogBytes, especially with multibyte UTF-8 output
  • ➕ Avoids under/over-truncation when logs include non-ASCII characters
  • ➖ Slightly more code complexity (buffer management)
  • ➖ Most current tests/logs are ASCII; benefit may be marginal unless unicode-heavy logs are expected
3. Stronger workspace containment check via realpath
  • ➕ Prevents symlink-based escape from workspace (realpath-resolved path containment)
  • ➕ Hardens security boundary beyond simple relative() prefix checks
  • ➖ Requires filesystem access and can fail in edge cases (missing paths)
  • ➖ More complexity; may be unnecessary if workspace is trusted/ephemeral in current threat model

Recommendation: The PR’s approach is solid for Wave 4: minimal dependencies, explicit security checks, and comprehensive tests. If this executor will be used in less-trusted workspaces, consider upgrading the cwd containment check to realpath-based validation and switching log truncation to byte-accurate accounting; otherwise the current implementation is a reasonable, reviewable baseline.

Files changed (13) +1246 / -28

Enhancement (5) +402 / -0
allowlist.tsImplement CommandAllowlist + createAllowlist factory +38/-0

Implement CommandAllowlist + createAllowlist factory

• Implements a deterministic allowlist that matches either absolute-path entries exactly or bare-name entries against the command basename; exposes readonly entries and rejects empty commands.

packages/runtime-host/src/allowlist.ts

config.tsDefine HostExecutorConfig without per-run workspace/artifactDir fields +22/-0

Define HostExecutorConfig without per-run workspace/artifactDir fields

• Adds a strict config interface for enabling the executor, allowlist selection, bounded env forwarding/injection, maxLogBytes, and runAsUid validation expectations; documents that workspace/artifactDir arrive per ExecuteRequest.

packages/runtime-host/src/config.ts

errors.tsAdd runtime-host error classes with stable codes +31/-0

Add runtime-host error classes with stable codes

• Introduces HostExecutorError base class with code/context and two concrete subclasses: HostTimeoutError (HOST_TIMEOUT) and CommandNotAllowedError (COMMAND_NOT_ALLOWED).

packages/runtime-host/src/errors.ts

host-executor.tsImplement HostExecutor: validation, spawn, timeout grace, env/cwd bounds, artifacts, log truncation +305/-0

Implement HostExecutor: validation, spawn, timeout grace, env/cwd bounds, artifacts, log truncation

• Implements the @sverka/runtime Executor interface for host processes with construction-time privilege escalation checks (runAsUid != 0; disallow sudo/su). Executes operations by validating type/timeout/allowlist, resolving a workspace-contained cwd, building a bounded env, spawning the child process with timeout (SIGTERM then SIGKILL after grace), truncating logs, and copying declared artifacts into request.artifactDir while reporting missing artifacts in the result error.

packages/runtime-host/src/host-executor.ts

index.tsExpose runtime-host public API surface +6/-0

Expose runtime-host public API surface

• Exports HostExecutor, createAllowlist/CommandAllowlist, HostExecutorConfig type, and error classes from a single package entrypoint.

packages/runtime-host/src/index.ts

Tests (5) +566 / -0
allowlist.test.tsAdd allowlist unit tests for deterministic command matching +45/-0

Add allowlist unit tests for deterministic command matching

• Covers bare-name basename matching, absolute-path exact matching, empty allowlist behavior, and entry exposure via .entries.

packages/runtime-host/src/tests/allowlist.test.ts

errors.test.tsAdd error hierarchy tests for runtime-host errors +54/-0

Add error hierarchy tests for runtime-host errors

• Validates HostExecutorError fields (name/code/context) and subclass behavior for HostTimeoutError and CommandNotAllowedError, including optional context.

packages/runtime-host/src/tests/errors.test.ts

fixtures.tsAdd test fixtures for PlanOperation, ExecuteRequest, and default config +60/-0

Add test fixtures for PlanOperation, ExecuteRequest, and default config

• Provides helpers to construct minimal host operations and requests plus a default HostExecutorConfig with a permissive allowlist and PATH forwarding for test runs.

packages/runtime-host/src/tests/helpers/fixtures.ts

host-executor.test.tsAdd end-to-end HostExecutor behavior tests (spawn, env, timeout, artifacts) +360/-0

Add end-to-end HostExecutor behavior tests (spawn, env, timeout, artifacts)

• Adds comprehensive coverage for canExecute gating, spawn output capture, non-zero exits, timeout kill behavior, bounded env forwarding (envAllowlist/request.env/request.credentials), workspace-constrained workingDir, privilege escalation checks, artifact copying, log truncation, spawn errors, and dispose no-op.

packages/runtime-host/src/tests/host-executor.test.ts

public-api.test.tsAdd public API export tests for runtime-host +47/-0

Add public API export tests for runtime-host

• Ensures HostExecutor, createAllowlist, and error classes are exported and usable, and performs compile-time checks for exported types.

packages/runtime-host/src/tests/public-api.test.ts

Documentation (2) +269 / -23
wave-04-runtime-host-plan.mdAdd Wave 4 implementation plan for runtime-host HostExecutor +248/-0

Add Wave 4 implementation plan for runtime-host HostExecutor

• Introduces a detailed engineering plan covering scope, file layout, TDD slices, error codes, edge cases, and build/test gates. Documents spec amendments (request.env/request.credentials, request.workspace/artifactDir) and explicitly excludes retry/setuid as scheduler/container responsibilities.

engdocs/architecture/wave-04-runtime-host-plan.md

spec.mdAmend Spec 05 to match built runtime contract (request-scoped env/credentials/paths) +21/-23

Amend Spec 05 to match built runtime contract (request-scoped env/credentials/paths)

• Updates the spec to clarify retry is scheduler-owned, and switches env/credentials and workspace/artifactDir references from operation/config fields to ExecuteRequest fields. Updates test plan commands to use bun run test via nx/vitest and adjusts environment/working-directory/artifact sections accordingly.

specs/05-runtime-host/spec.md

Other (1) +9 / -5
package.jsonAlign runtime-host dist outputs and add workspace deps +9/-5

Align runtime-host dist outputs and add workspace deps

• Updates main/module/types/exports to point at dist/index.mjs and dist/index.d.mts for ESM consistency. Adds @sverka/runtime and @sverka/ir as workspace dependencies.

packages/runtime-host/package.json

@codacy-production

codacy-production Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 70 complexity · 0 duplication

Metric Results
Complexity 70
Duplication 0

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@codacy-production codacy-production Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request is currently not up to standards. While the functional intent to implement the HostExecutor is correctly aligned with the architecture plan, the current implementation contains high-severity security flaws, including path traversal vulnerabilities in artifact collection and potential Denial-of-Service (DoS) via memory exhaustion in the logging mechanism.

Additionally, the execute method in host-executor.ts has become overly complex (cyclomatic complexity of 14), making it difficult to maintain and test. Codacy analysis reports 315 new issues and several code clones, indicating that significant cleanup and refactoring are required before this can be safely merged. The core executor logic is identified as high-risk and requires improved test coverage to validate boundary conditions and security constraints.

About this PR

  • The PR introduces 315 new static analysis issues and 8 code clones. A systemic cleanup is required to meet the project's quality standards. Additionally, the core host-executor.ts file is significantly more complex than recommended, which likely contributed to the high-severity logic errors found during review.

Test suggestions

  • HostExecutor.canExecute returns false when disabled or given a non-host operation type
  • HostExecutor.canExecute validates command against allowlist and ensures timeoutSeconds is positive
  • Process execution captures combined stdout/stderr and returns success status on exit code 0
  • Process execution returns failure status and correct exit code for non-zero exits
  • Timeouts trigger SIGTERM followed by SIGKILL after the 2s grace period
  • Environment variables from host are filtered through envAllowlist, while request env/credentials are fully forwarded
  • Operation working directory relative to workspace is honored but blocked if it attempts to escape via '..'
  • Constructor throws PRIVILEGE_ESCALATION if runAsUid is 0 or allowlist contains sudo/su
  • Declared artifacts are copied to artifactDir and missing files are reported in the result error
  • Logs are truncated and tagged with a notice when exceeding maxLogBytes
  • Increase unit test coverage for HostExecutor logic paths (currently identified as uncovered and complex)
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Increase unit test coverage for HostExecutor logic paths (currently identified as uncovered and complex)

TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback

Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
@qodo-code-review

qodo-code-review Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Timeout leaks descendant processes ⊘ Outdated 🐞 Bug ☼ Reliability
Description
Timeout handling signals only the direct child PID, so descendants started by the command can
continue running after the operation fails. These leaked processes can keep consuming resources or
modifying the workspace during retries and later operations.
Code

packages/runtime-host/src/host-executor.ts[R214-217]

+        child.kill("SIGTERM");
+        setTimeout(() => {
+          if (!child.killed) {
+            child.kill("SIGKILL");
Evidence
The process is spawned without process-group management and timeout calls kill() only on the
direct child. The implementation plan explicitly requires timeout cleanup not to leak the process.

packages/runtime-host/src/host-executor.ts[206-220]
engdocs/architecture/wave-04-runtime-host-plan.md[210-210]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The timeout path terminates only the direct `ChildProcess`; helper and background processes spawned by it can survive. Timed-out host operations must clean up the complete process tree using platform-appropriate behavior.

## Issue Context
On Unix, create and terminate an isolated process group; provide an equivalent tree-termination strategy on Windows. Test a command that starts a long-lived descendant and verify no descendant remains after timeout.

## Fix Focus Areas
- packages/runtime-host/src/host-executor.ts[206-220]
- packages/runtime-host/src/__tests__/host-executor.test.ts[114-136]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Symlink bypasses workspace cwd 🐞 Bug ⛨ Security
Description
resolveCwd checks only lexical path components, so an in-workspace symlink targeting an external
directory passes validation and becomes the child cwd. This violates the explicit
workspace-constrained working-directory guarantee.
Code

packages/runtime-host/src/host-executor.ts[R152-156]

+    const resolved = isAbsolute(op.workingDir)
+      ? op.workingDir
+      : resolve(workspace, op.workingDir);
+    const rel = relative(workspace, resolved);
+    if (rel.startsWith("..")) {
Evidence
The implementation never resolves filesystem symlinks before accepting cwd. The host-executor
contract explicitly requires cwd to remain within request.workspace.

packages/runtime-host/src/host-executor.ts[148-164]
specs/05-runtime-host/spec.md[156-167]
specs/05-runtime-host/spec.md[236-238]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Lexical `resolve`/`relative` checks do not account for symlinks. Canonicalize both the workspace and requested existing working directory, then enforce containment using path-component boundaries before spawning.

## Issue Context
Define deliberate behavior for nonexistent working directories, and add a test where a symlink inside the workspace points outside it.

## Fix Focus Areas
- packages/runtime-host/src/host-executor.ts[148-164]
- packages/runtime-host/src/__tests__/host-executor.test.ts[194-232]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. SIGKILL grace timer relies on unreliable child.killed 🐞 Bug ☼ Reliability
Description
After sending SIGTERM, the grace-period callback only sends SIGKILL when !child.killed, but
Node.js sets child.killed to true as soon as the kill signal is successfully dispatched rather
than when the process actually exits. As a result, a child that ignores SIGTERM will never receive
SIGKILL and execute() can remain pending indefinitely despite the mandatory timeout.
Code

packages/runtime-host/src/host-executor.ts[R212-220]

+      const timer = setTimeout(() => {
+        timedOut = true;
+        child.kill("SIGTERM");
+        setTimeout(() => {
+          if (!child.killed) {
+            child.kill("SIGKILL");
+          }
+        }, GRACE_PERIOD_MS);
+      }, timeoutSeconds * 1000);
Evidence
The implementation calls child.kill('SIGTERM') and later (after the grace delay) decides whether
to send SIGKILL by checking child.killed. Node’s documentation for ChildProcess.killed indicates
it reflects whether a signal was successfully sent, not whether the process has terminated, so by
the time the grace timer fires the property will already be true from the earlier SIGTERM dispatch;
this makes the SIGKILL path effectively unreachable for processes that don’t exit on SIGTERM and
explains how the timeout safety mechanism can fail to complete.

packages/runtime-host/src/host-executor.ts[212-220]
🌐 The subprocess.killed property is set after subprocess.kill() successfully sends a signal and does not indicate that the child has terminated.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The timeout grace-period logic in `spawnProcess` incorrectly uses `child.killed` to decide whether to send SIGKILL after sending SIGTERM. In Node.js, `child.killed` becomes true once the signal is successfully dispatched (not when the process exits), so a SIGTERM-resistant child may never be force-killed and `execute()` may remain pending indefinitely.

## Issue Context
The timeout handling is intended to: send SIGTERM, wait `GRACE_PERIOD_MS`, then send SIGKILL if the process hasn’t exited (per the plan doc requirement of “SIGTERM, then SIGKILL after 2s grace”). To implement this correctly, process termination/closure must be tracked independently (e.g., via `close`/`exit` events) rather than using `child.killed`. Also ensure timers are managed safely: clear the grace timer if the process exits before it elapses, and clear both timeout timers during terminal event handling to avoid attempting to kill an already-exited process. Add a test that spawns a child which handles or ignores SIGTERM to verify SIGKILL is issued after the grace period when needed.

## Fix Focus Areas
- packages/runtime-host/src/host-executor.ts[212-220]
- packages/runtime-host/src/host-executor.ts[212-244]
- packages/runtime-host/src/host-executor.ts[243-273]
- packages/runtime-host/src/__tests__/host-executor.test.ts[114-136]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View action required (1)
4. Log limit leaves memory unbounded 🐞 Bug ☼ Reliability
Description
The data handlers accumulate all stdout and stderr until process close and apply maxLogBytes only
afterward. A noisy child can exhaust the runtime process's memory despite the configured log limit.
Code

packages/runtime-host/src/host-executor.ts[R222-224]

+      child.stdout?.on("data", (data: Buffer) => {
+        stdout += data.toString();
+      });
Evidence
Both streams append without a size check for the process lifetime, and truncation occurs only in the
close handler. Thus maxLogBytes does not bound memory usage.

packages/runtime-host/src/host-executor.ts[201-227]
packages/runtime-host/src/host-executor.ts[243-278]
packages/runtime-host/src/config.ts[18-19]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Post-process truncation limits only the returned string, not memory consumed while the child runs. Enforce a combined byte budget in the stream handlers, retain only data within that budget, and record that excess output was discarded.

## Issue Context
The implementation must continue draining both pipes to avoid blocking the child while keeping retained data bounded. Add a test that emits substantially more than the configured limit.

## Fix Focus Areas
- packages/runtime-host/src/host-executor.ts[201-278]
- packages/runtime-host/src/__tests__/host-executor.test.ts[299-314]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. Artifact copy lacks path-traversal containment checks 🐞 Bug ⛨ Security
Description
collectArtifacts constructs artifact source paths from plan-controlled artifact.path (including
accepting absolute paths) and destination paths from artifact.name ?? artifact.path by simple
join operations without verifying containment within workspace/artifactDir, unlike
resolveCwd which explicitly rejects escaping paths. As a result, .. segments or absolute paths
can cause artifact collection to read from outside the workspace and write outside artifactDir,
potentially overwriting any file writable by the executor user.
Code

packages/runtime-host/src/host-executor.ts[R289-297]

+    for (const artifact of op.artifacts) {
+      const src = isAbsolute(artifact.path)
+        ? artifact.path
+        : join(workspace, artifact.path);
+      const dest = join(artifactDir, artifact.name ?? artifact.path);
+      try {
+        await mkdir(dirname(dest), { recursive: true });
+        await copyFile(src, dest);
+        collected.push(dest);
Evidence
ArtifactDeclaration path/name are plan-controlled strings with no format restriction
(packages/ir/src/plan.ts lines 90-94), and current validation does not impose additional artifact
path/name constraints. In collectArtifacts, the source path is derived by using artifact.path
directly when absolute or by joining it to workspace when relative, and the destination is derived
by joining artifactDir with artifact.name ?? artifact.path; because there is no
path.relative/..-prefix containment check (and parent directories are created before copying),
crafted values like ../... or absolute paths can escape these directories, in contrast to the
explicit WORKDIR_OUTSIDE_WORKSPACE guard in resolveCwd nearby.

packages/runtime-host/src/host-executor.ts[148-164]
packages/ir/src/plan.ts[90-94]
packages/runtime-host/src/host-executor.ts[289-300]
packages/ir/src/validate.ts[170-326]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`collectArtifacts` resolves artifact source paths (`operation.artifacts[].path`) and destination paths (`artifact.name ?? artifact.path`) without enforcing that the resolved paths remain inside `workspace` and `artifactDir` respectively. This allows path traversal (`..`), absolute paths, and potentially symlink-based escapes to read files from outside the workspace and write/copy outside the configured artifact directory, including overwriting any file writable by the executor user.

## Issue Context
- The IR permits arbitrary strings for artifact `name` and `path`, and current plan validation does not constrain them.
- The same runtime-host file already implements a containment pattern for `operation.workingDir` in `resolveCwd` (using `path.relative` and rejecting `..`-prefixed results / outside-workspace paths), but `collectArtifacts` does not apply an equivalent check to artifact source/destination resolution.
- Destination handling creates parent directories before copying, which makes destination traversal especially risky.
- Add/extend tests to cover `../` traversal, absolute paths, and symlink-based destination escapes.

## Fix Focus Areas
- packages/runtime-host/src/host-executor.ts[281-304]
- packages/runtime-host/src/__tests__/host-executor.test.ts[268-297]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Log truncation uses string length instead of byte length 🐞 Bug ≡ Correctness
Description
truncateLogs enforces maxLogBytes using logs.length/slice, which operate on UTF-16 code
units rather than bytes, so non-ASCII output can exceed the configured byte limit and truncation can
split multi-byte characters. It also appends TRUNCATION_NOTICE after slicing to maxLogBytes,
causing the returned logs to exceed maxLogBytes even for ASCII and violating the stated invariant
that output must never exceed the limit.
Code

packages/runtime-host/src/host-executor.ts[R276-279]

+  private truncateLogs(logs: string): string {
+    if (logs.length <= this.maxLogBytes) return logs;
+    return logs.slice(0, this.maxLogBytes) + TRUNCATION_NOTICE;
+  }
Evidence
The configuration in config.ts defines maxLogBytes as a maximum log size in bytes, but
truncateLogs measures and truncates via String.prototype.length and slice, which count UTF-16
code units rather than UTF-8 bytes; this means strings containing multi-byte characters can remain
over the true byte budget and truncation may cut through a multi-byte character or surrogate pair.
Additionally, the runtime-host plan (engdocs/architecture/wave-04-runtime-host-plan.md §7) states
logs must “never exceed maxLogBytes,” yet the implementation slices to maxLogBytes and then
appends TRUNCATION_NOTICE, making the final output longer than the configured maximum by the
notice length.

packages/runtime-host/src/config.ts[18-19]
engdocs/architecture/wave-04-runtime-host-plan.md[211-212]
packages/runtime-host/src/host-executor.ts[276-279]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`truncateLogs` currently checks and truncates logs using JavaScript string code-unit length (`logs.length` / `slice`), even though `maxLogBytes` is defined as a byte limit. This can allow returned logs to exceed `maxLogBytes` (especially for non-ASCII text) and can also split multi-byte characters/surrogate pairs; additionally, the function appends `TRUNCATION_NOTICE` after slicing to the full limit, guaranteeing the final returned string exceeds `maxLogBytes` even for ASCII.

## Issue Context
- `maxLogBytes` is documented as a maximum log size **in bytes**.
- The architecture/implementation plan requires the final returned log output to **never exceed `maxLogBytes`**, including any truncation notice.
- Define sensible behavior when `maxLogBytes` is smaller than `TRUNCATION_NOTICE` (e.g., return a truncated notice-only string, return an empty string, or omit the notice), but ensure the invariant still holds.

## Fix Focus Areas
- packages/runtime-host/src/host-executor.ts[13-15]
- packages/runtime-host/src/host-executor.ts[276-279]
- packages/runtime-host/src/__tests__/host-executor.test.ts[299-314]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

7. Spawn error handler discards captured stdout/stderr 🐞 Bug ◔ Observability
Description
In the child's error event handler, logs is set solely to stderr: ${err.message}, discarding
any stdout/stderr output that was already buffered before the error fired, and mislabeling a
spawn-level error (e.g., ENOENT) as stderr content. This reduces diagnostic accuracy for partial
output that occurred before a spawn failure.
Code

packages/runtime-host/src/host-executor.ts[R229-241]

+      child.on("error", (err) => {
+        clearTimeout(timer);
+        const durationMs = Date.now() - start;
+        const logs = this.truncateLogs(`stderr: ${err.message}`);
+        resolvePromise({
+          operationId,
+          status: "failure",
+          durationMs,
+          logs,
+          artifacts: [],
+          error: `spawn error: ${err.message}`,
+        });
+      });
Evidence
The 'close' handler correctly builds logs from the accumulated stdout/stderr buffers (`const rawLogs
= stdout + (stderr ? "\n" + stderr : "")`), but the 'error' handler ignores those same buffers
entirely and instead constructs logs from just the error message prefixed with the literal string
'stderr:', which is inconsistent and misleading since ChildProcess 'error' events are not stderr
stream data.

packages/runtime-host/src/host-executor.ts[243-247]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The child process `error` event handler builds `logs` only from the error message (mislabeled with a `stderr:` prefix), discarding any stdout/stderr already captured before the failure.

## Issue Context
The `close` handler builds logs correctly by concatenating captured stdout and stderr; the `error` handler should follow the same pattern and additionally note the spawn error distinctly.

## Fix Focus Areas
- packages/runtime-host/src/host-executor.ts[229-241]

Build `logs` from the same `stdout`/`stderr` concatenation used in the close handler, and append the spawn error message as a separate line (not prefixed with `stderr:`) so partial output isn't lost and the error is clearly attributed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
✅ Web pages:
  +2 more
Review mode: 🧠 Deep: This introduces security-sensitive process execution with allowlisting, credential/env handling, timeouts, artifacts, and substantial independent logic across implementation and tests, making multiple subtle defects plausible.

Grey Divider

Tip of the day
💡 Did you know, you can group findings by type and pick your Finding display, from Minimal to Full

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
@codeant-ai

codeant-ai Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed d2d6fd9 Aug 11, 2026 · 10:38 10:38
✅ Incremental review completed 34f1f80 Aug 11, 2026 · 08:20 08:20
✅ Incremental review completed 8d881e2 Aug 11, 2026 · 06:23 06:23
✅ Incremental review completed aca7737 Aug 10, 2026 · 23:46 23:46
✅ Incremental review completed 7191fa4 Aug 10, 2026 · 21:28 21:29

@baz-reviewer

baz-reviewer Bot commented Aug 9, 2026 •

Copy link
Copy Markdown

Merger

Needs Review

The shipped host executor still has concrete high-risk flaws, including allowlist bypasses for absolute paths, artifact path traversal, and broken SIGKILL escalation via child.killed; these remain blockers despite resolved discussions. CI also did not run for this non-trivial security-sensitive change.

Commit 5908184 · Evaluated 2026-08-11 10:51 UTC

Review this PR on Baz | Customize your next review

@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Aug 9, 2026
Comment thread packages/runtime-host/src/config.ts
Comment thread packages/runtime-host/src/host-executor.ts Outdated
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 33 files

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread packages/runtime-host/src/allowlist.ts
Comment thread engdocs/architecture/wave-04-runtime-host-plan.md
Comment thread engdocs/architecture/wave-04-runtime-host-plan.md
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread engdocs/architecture/wave-04-runtime-host-plan.md
Comment thread specs/05-runtime-host/spec.md
Comment thread packages/runtime-host/src/errors.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-docker/package.json
Comment thread packages/runtime-host/src/host-executor.ts
This was referenced Aug 9, 2026
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from 7108fe3 to b49a057 Compare August 10, 2026 20:19
@codeant-ai codeant-ai Bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Aug 10, 2026
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from b49a057 to 56bd3d8 Compare August 10, 2026 20:26
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from 56bd3d8 to 8ffc6fd Compare August 10, 2026 20:44
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from 8ffc6fd to df89511 Compare August 10, 2026 20:52
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch 2 times, most recently from 841ecfc to ef84f33 Compare August 10, 2026 21:04
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from 7191fa4 to aca7737 Compare August 10, 2026 23:46
@codeant-ai codeant-ai Bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Aug 10, 2026
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from 4c3b10a to 8d881e2 Compare August 11, 2026 06:23
@codeant-ai codeant-ai Bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Aug 11, 2026
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from 8d881e2 to 34f1f80 Compare August 11, 2026 08:19
@codeant-ai codeant-ai Bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Aug 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 12

🤖 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 `@engdocs/architecture/wave-04-runtime-host-plan.md`:
- Around line 163-165: Update the working-directory containment logic in the
runtime host plan to canonicalize both request.workspace and the resolved
operation.workingDir with realpath before checking containment. Reject relative
results equal to "..", beginning with ".." plus the platform separator, or
absolute paths; add tests covering sibling-prefix paths and symlink escapes.

In `@package.json`:
- Line 19: Update the workspace-local tsdown declaration in
packages/runtime-docker/package.json to match the root package.json pin of
0.22.14, or ensure the lockfile enforces that single version across the
workspace. Preserve the existing build dependency configuration while preventing
the caret range from resolving a different version.

In `@packages/core/package.json`:
- Line 18: Update the lint command in the Nx target of project.json to match the
package.json lint script and remove the obsolete --ext .ts argument, while
preserving the existing eslint src invocation.

In `@packages/runtime-host/src/__tests__/host-executor.test.ts`:
- Around line 299-313: The HostExecutor output handling must enforce maxLogBytes
during collection, not after accumulating complete stdout and stderr. Update the
execute/log collection flow and truncateLogs logic to use a bounded buffer that
continues draining both streams, reserves space for the "[log truncated]"
notice, and never exceeds maxLogBytes; tighten the test assertion to require
result.logs.length to be at most maxLogBytes.
- Around line 115-127: Update HostExecutor timeout handling and spawnProcess
termination to track actual child process closure rather than relying on
child.killed, clear the SIGKILL grace timer when the process closes, and
escalate to SIGKILL for the process group or entire process tree when SIGTERM is
ignored. Ensure descendants are terminated so captured stdio closes, and add
coverage for both a SIGTERM-ignoring child and a persistent descendant.

In `@packages/runtime-host/src/allowlist.ts`:
- Around line 27-35: Update Allowlist.isAllowed so non-absolute entries match
only commands that are themselves bare names, never an absolute command path;
retain exact matching for absolute allowlist entries. Adjust the corresponding
allowlist test covering bare entries and absolute commands to verify
/workspace/tools/node is rejected when only "node" is allowed.

In `@packages/runtime-host/src/host-executor.ts`:
- Around line 55-56: Update the timeout validation around
operation.timeoutSeconds to reject non-finite values and values whose
millisecond conversion exceeds Node’s supported timer range before calling
spawnProcess. Preserve the existing rejection for undefined and non-positive
values, returning the same MISSING_TIMEOUT behavior for every unsupported
timeout.
- Around line 147-148: Update the path validation around relative() in the host
executor to use path-segment boundaries: reject only rel === "..", rel beginning
with ".." followed by the platform separator, or an absolute rel. Preserve valid
child paths such as "..cache" and use the existing separator/path utilities.
- Around line 204-211: Update the timeout logic around the child process so the
grace-period callback checks whether the child’s close event has fired, rather
than relying on child.killed. Track the close state from the child process close
handler and send SIGKILL after GRACE_PERIOD_MS when it remains open, preserving
the existing SIGTERM-then-grace-period escalation in the executor flow.
- Around line 27-47: The HostExecutor constructor currently validates runAsUid
but does not apply it to child processes. Update the child-process spawn call to
pass config.runAsUid through the uid option, and reject configurations with an
unset runAsUid when the executor is running as root. Add tests covering the
spawned UID and this fail-closed validation path.
- Around line 158-181: Restrict request.env in buildEnv before merging it into
the child environment by applying a dedicated request-environment allowlist.
Reject PATH, NODE_OPTIONS, and dynamic-loader variables such as LD_PRELOAD, and
reject any keys colliding with config.env or request.credentials so protected
values cannot be overwritten. Preserve the existing merge behavior only for
validated request environment entries.

In `@specs/05-runtime-host/spec.md`:
- Around line 313-315: Update the fenced command block under Commands in
specs/05-runtime-host/spec.md with blank lines immediately before and after the
fence. In host-executor.ts, update resolveCwd to realpath the workspace and
candidate, reject escaped relative paths including "..", parent-prefixed paths,
and absolute paths; resolve bare commands before buildEnv merges request.env.
Pass validated runAsUid to spawn with platform-specific validation and tests,
track actual child exit instead of child.killed before SIGKILL, bound
stdout/stderr capture before truncateLogs, and constrain artifact source and
destination paths to their request-scoped roots.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 64b586cc-2410-4156-b69c-fc3cc44420fd

📥 Commits

Reviewing files that changed from the base of the PR and between 3629bde and 34f1f80.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • engdocs/architecture/wave-04-runtime-host-plan.md
  • package.json
  • packages/checks/package.json
  • packages/cli/package.json
  • packages/compiler-earthly/package.json
  • packages/compiler-github/package.json
  • packages/compiler-gitlab/package.json
  • packages/core/package.json
  • packages/core/src/internal/plan.ts
  • packages/findings/package.json
  • packages/ir/package.json
  • packages/planner/package.json
  • packages/policy/package.json
  • packages/runtime-docker/package.json
  • packages/runtime-host/package.json
  • packages/runtime-host/src/__tests__/allowlist.test.ts
  • packages/runtime-host/src/__tests__/errors.test.ts
  • packages/runtime-host/src/__tests__/helpers/fixtures.ts
  • packages/runtime-host/src/__tests__/host-executor.test.ts
  • packages/runtime-host/src/__tests__/public-api.test.ts
  • packages/runtime-host/src/allowlist.ts
  • packages/runtime-host/src/config.ts
  • packages/runtime-host/src/errors.ts
  • packages/runtime-host/src/host-executor.ts
  • packages/runtime-host/src/index.ts
  • packages/runtime-podman/package.json
  • packages/runtime-remote/package.json
  • packages/runtime/package.json
  • packages/sdk/package.json
  • specs/05-runtime-host/spec.md
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Codacy Static Code Analysis
🧰 Additional context used
🪛 ast-grep (0.45.1)
packages/runtime-host/src/host-executor.ts

[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

🪛 LanguageTool
engdocs/architecture/wave-04-runtime-host-plan.md

[grammar] ~40-~40: Ensure spelling is correct
Context: ...ostExecutorError→HostTimeoutError, CommandNotAllowedError. - Public re-exports from src/index.ts...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~171-~171: Ensure spelling is correct
Context: ...alidate in constructor; do not actually setuid. ### Slice I — Artifacts + log truncation 18....

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.23.2)
specs/05-runtime-host/spec.md

[warning] 314-314: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

engdocs/architecture/wave-04-runtime-host-plan.md

[warning] 76-76: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 96-96: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 103-103: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 104-104: Ordered list item prefix
Expected: 1; Actual: 3; Style: 1/2/3

(MD029, ol-prefix)


[warning] 108-108: Ordered list item prefix
Expected: 2; Actual: 4; Style: 1/2/3

(MD029, ol-prefix)


[warning] 113-113: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 114-114: Ordered list item prefix
Expected: 1; Actual: 5; Style: 1/2/3

(MD029, ol-prefix)


[warning] 116-116: Ordered list item prefix
Expected: 2; Actual: 6; Style: 1/2/3

(MD029, ol-prefix)


[warning] 118-118: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 119-119: Ordered list item prefix
Expected: 1; Actual: 7; Style: 1/2/3

(MD029, ol-prefix)


[warning] 124-124: Ordered list item prefix
Expected: 2; Actual: 8; Style: 1/2/3

(MD029, ol-prefix)


[warning] 132-132: Ordered list item prefix
Expected: 3; Actual: 9; Style: 1/2/3

(MD029, ol-prefix)


[warning] 137-137: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 138-138: Ordered list item prefix
Expected: 1; Actual: 10; Style: 1/2/3

(MD029, ol-prefix)


[warning] 142-142: Ordered list item prefix
Expected: 2; Actual: 11; Style: 1/2/3

(MD029, ol-prefix)


[warning] 146-146: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 147-147: Ordered list item prefix
Expected: 1; Actual: 12; Style: 1/2/3

(MD029, ol-prefix)


[warning] 152-152: Ordered list item prefix
Expected: 2; Actual: 13; Style: 1/2/3

(MD029, ol-prefix)


[warning] 156-156: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 157-157: Ordered list item prefix
Expected: 1; Actual: 14; Style: 1/2/3

(MD029, ol-prefix)


[warning] 163-163: Ordered list item prefix
Expected: 2; Actual: 15; Style: 1/2/3

(MD029, ol-prefix)


[warning] 167-167: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 168-168: Ordered list item prefix
Expected: 1; Actual: 16; Style: 1/2/3

(MD029, ol-prefix)


[warning] 171-171: Ordered list item prefix
Expected: 2; Actual: 17; Style: 1/2/3

(MD029, ol-prefix)


[warning] 173-173: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 174-174: Ordered list item prefix
Expected: 1; Actual: 18; Style: 1/2/3

(MD029, ol-prefix)


[warning] 179-179: Ordered list item prefix
Expected: 2; Actual: 19; Style: 1/2/3

(MD029, ol-prefix)


[warning] 181-181: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 182-182: Ordered list item prefix
Expected: 1; Actual: 20; Style: 1/2/3

(MD029, ol-prefix)


[warning] 183-183: Ordered list item prefix
Expected: 2; Actual: 21; Style: 1/2/3

(MD029, ol-prefix)


[warning] 184-184: Ordered list item prefix
Expected: 3; Actual: 22; Style: 1/2/3

(MD029, ol-prefix)

🔇 Additional comments (29)
package.json (2)

15-18: LGTM!

Also applies to: 20-20, 22-22


21-21: 🎯 Functional Correctness

Verify the typescript-eslint downgrade.

Line 21 pins typescript-eslint to 8.66.0, but the previous range was ^8.67.0. Confirm that this downgrade is intentional, that the lockfile resolves 8.66.0, and that it works with ESLint 9.39.5 and TypeScript 5.9.3.

packages/checks/package.json (1)

18-18: LGTM!

packages/cli/package.json (1)

18-18: LGTM!

packages/compiler-earthly/package.json (1)

18-18: LGTM!

packages/runtime-docker/package.json (2)

5-14: LGTM!

Also applies to: 18-18


21-24: 🗄️ Data Integrity & Integration

Verify the workspace:* dependency rewrite before publishing.

Lines 22-23 add workspace:* dependencies to a package with public exports. Confirm that the pack/publish workflow rewrites them to concrete versions in the packed manifest. Otherwise, consumers outside the workspace may fail to install the package.

packages/runtime-podman/package.json (1)

18-18: LGTM!

packages/runtime-remote/package.json (1)

18-18: LGTM!

packages/runtime/package.json (1)

18-18: LGTM!

packages/sdk/package.json (1)

18-18: LGTM!

packages/compiler-github/package.json (1)

18-18: LGTM!

packages/compiler-gitlab/package.json (1)

18-18: LGTM!

packages/core/src/internal/plan.ts (1)

2-2: LGTM!

packages/findings/package.json (1)

18-18: LGTM!

packages/ir/package.json (1)

18-18: LGTM!

packages/planner/package.json (1)

18-18: LGTM!

packages/policy/package.json (1)

18-18: LGTM!

engdocs/architecture/wave-04-runtime-host-plan.md (1)

1-162: LGTM!

Also applies to: 166-249

packages/runtime-host/src/__tests__/errors.test.ts (1)

1-54: LGTM!

packages/runtime-host/src/__tests__/helpers/fixtures.ts (1)

1-60: LGTM!

packages/runtime-host/src/__tests__/host-executor.test.ts (1)

1-114: LGTM!

Also applies to: 128-298, 314-360

packages/runtime-host/package.json (1)

5-24: LGTM!

packages/runtime-host/src/__tests__/public-api.test.ts (1)

1-47: LGTM!

packages/runtime-host/src/errors.ts (1)

6-30: LGTM!

packages/runtime-host/src/index.ts (1)

3-7: LGTM!

packages/runtime-host/src/host-executor.ts (2)

214-219: Bound log capture during process execution.

stdout and stderr remain unbounded until close. truncateLogs cannot prevent memory exhaustion during a noisy command.


281-289: Contain artifact source and destination paths.

artifact.path and artifact.name can escape workspace and artifactDir. Validate both resolved paths before copying.

packages/runtime-host/src/__tests__/allowlist.test.ts (1)

1-45: LGTM!

Comment thread engdocs/architecture/wave-04-runtime-host-plan.md
Comment thread package.json
Comment thread packages/core/package.json
Comment thread packages/runtime-host/src/__tests__/host-executor.test.ts
Comment thread packages/runtime-host/src/__tests__/host-executor.test.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread packages/runtime-host/src/host-executor.ts
Comment thread specs/05-runtime-host/spec.md
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from 34f1f80 to 26ef475 Compare August 11, 2026 08:54
@coderabbitai coderabbitai Bot mentioned this pull request Aug 11, 2026
3 tasks done
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from 26ef475 to d2d6fd9 Compare August 11, 2026 10:38
@codeant-ai codeant-ai Bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Aug 11, 2026
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from d2d6fd9 to d3ff091 Compare August 11, 2026 10:44
ThePlenkov and others added 3 commits August 11, 2026 10:50
HostExecutor implementation: allowlist enforcement, env/credential
passing, artifact collection, log truncation, timeout + SIGKILL grace.
47 tests pass across 4 files (allowlist, errors, host-executor, public-api).
Typecheck clean, build produces dist/index.mjs + dist/index.d.mts.
Reviewer approved (sv-gab). Spec 05 amended to match built runtime contract.

<details>
- 47 tests pass
- typecheck clean
- build green
- reviewer approved
</details>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Created eslint.config.mjs (TypeScript-aware, strict, ESM, ESLint 9 flat config)
- Added typescript-eslint dependency
- Fixed all per-package lint scripts: removed legacy --ext .ts flag (removed in ESLint 9)
- Fixed dead imports: core/plan.ts (OperationOutcome), ir/validate.ts (PlanOperation), runtime-host/host-executor.ts (HostTimeoutError)
- Relaxed no-unused-vars to warn for test files (standard practice)
- Lint now passes repo-wide

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…omplexity; pin devDeps

- Refactor HostExecutor.execute (62 lines → 17, complexity 14 → 3)
  by extracting validateRequest and finalizeResult helpers.
- Pin devDependency versions to resolve Codacy dependency-hijack warning.
- Fix missing OperationOutcome import in core/plan.ts from rebase.
@ThePlenkov
ThePlenkov force-pushed the wave-4-runtime-host branch from d3ff091 to 5908184 Compare August 11, 2026 10:50
@sonarqubecloud

Copy link
Copy Markdown

@ThePlenkov
ThePlenkov merged commit f9f233b into main Aug 11, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

baz: needs review size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant