Skip to content

[Feature] Added parallelism to ventis build for speedup - #22

Open
Saaketh0 wants to merge 1 commit into
mainfrom
ventis-build-speedup
Open

[Feature] Added parallelism to ventis build for speedup#22
Saaketh0 wants to merge 1 commit into
mainfrom
ventis-build-speedup

Conversation

@Saaketh0

@Saaketh0 Saaketh0 commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Ventis build now builds all agent and workflow Docker images in a single parallel docker buildx bake pass instead of sequential docker build calls, cutting build time significantly and letting BuildKit share cached layers (e.g. pip install) across agents with identical dependencies.

If Buildx isn't available on the host, it falls back to today's sequential build behavior. Every generated bake target sets output: type=docker so images always land in the local image store, matching what ventis deploy expects.

Also fixed: agent/workflow Dockerfiles now use JSON-array (exec) form for CMD instead of shell form, so containers respond correctly to OS signals.

Summary by CodeRabbit

  • New Features

    • Docker images now build in parallel with Docker Buildx when available.
    • Builds automatically fall back to sequential Docker commands when Buildx is unavailable.
    • Builds skip projects without agents or required entrypoints.
  • Improvements

    • Generated containers now use more reliable command execution.
    • Documentation now explains the optional Docker Buildx requirement.

@Saaketh0 Saaketh0 added the enhancement New feature or request label Jul 27, 2026
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

ventis build now batches agent and workflow image builds through Docker Buildx when available, falls back to sequential Docker builds otherwise, and generates exec-form container commands. Tests cover both paths and no-op conditions.

Changes

Docker image build flow

Layer / File(s) Summary
Generated container commands
ventis/stub_generator.py
Generated agent and workflow Dockerfiles now use exec-form Python CMD instructions.
Buildx orchestration and fallback
ventis/cli.py
cmd_build collects targets, writes a Buildx bake file, invokes docker buildx bake when available, and otherwise runs sequential docker build commands.
Build validation and metadata
tests/test_cli.py, README.md, .dockerignore, .gitignore
CLI tests cover Buildx, fallback, empty-agent, and missing-entrypoint behavior; documentation and ignore rules are updated for the build setup.

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

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ventis_build
  participant Docker
  participant BuildxBakeFile
  User->>ventis_build: run ventis build
  ventis_build->>Docker: probe Docker and Buildx
  alt Buildx available
    ventis_build->>BuildxBakeFile: write bake targets
    ventis_build->>Docker: run docker buildx bake
  else Buildx unavailable
    ventis_build->>Docker: run sequential docker build commands
  end
Loading

Suggested reviewers: iidsample

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: making ventis build parallel for faster builds.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 ventis-build-speedup

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.

@coderabbitai
coderabbitai Bot requested a review from iidsample July 27, 2026 18:14

@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: 2

🧹 Nitpick comments (5)
.gitignore (1)

43-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider committing uv.lock instead. For an installable application, a tracked lock file gives contributors and CI reproducible dependency resolution; ignoring it is usually reserved for libraries.

🤖 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 @.gitignore at line 43, Update the .gitignore entry for uv.lock so the lock
file is no longer ignored, allowing it to be committed and used for reproducible
dependency resolution.
ventis/cli.py (2)

321-327: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

docker_context leaks across loop iterations.

docker_context is assigned inside both branches, but every continue path (missing workflow_file, missing entrypoint, no matching YAML, etc.) skips the assignment while leaving the previous iteration's value bound. Today each continue also skips this append, so it is not currently reachable — but the append sits outside the if/else, so any future early-exit refactor silently registers the wrong context. Initializing docker_context = None per iteration and appending inside each branch would remove the hazard.

🤖 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 `@ventis/cli.py` around lines 321 - 327, Initialize docker_context to None at
the start of each loop iteration and restructure the branch-specific flow so
bake_targets.append executes only within the branch that successfully assigns a
valid context. Preserve all existing continue paths for missing workflow files,
entrypoints, or matching YAML.

248-250: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Step numbering skips 3. Steps go 1, 2, 4, 5 — worth renumbering while this block is being touched.

🤖 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 `@ventis/cli.py` around lines 248 - 250, Correct the step numbering in the
surrounding CLI workflow comments so the sequence is consecutive, adding or
restoring Step 3 before the existing Step 4 section near bake_targets and
updating subsequent labels as needed.
tests/test_cli.py (2)

240-270: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Assertions are weaker than intended. Both tests assert call[0] == "docker" is never seen, which passes trivially even if the build loop malfunctions — the only recorded call is the protoc invocation. Asserting docker_calls contains exactly the protoc call would pin the no-op behavior.

🤖 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 `@tests/test_cli.py` around lines 240 - 270, Strengthen the assertions in
test_build_with_no_agents_builds_nothing and
test_build_skips_agent_without_entrypoint to require docker_calls exactly
matches the expected protoc invocation, rather than merely containing no Docker
call. Preserve the existing no-op build behavior while ensuring unexpected or
missing recorded calls fail these tests.

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

One mock for both _docker_available probes hides the docker-missing case.

cmd_build calls _docker_available() twice with different probe commands (docker info, then docker buildx version). Patching with a flat return_value makes both return the same thing, so the only fallback scenario exercised is "Docker entirely absent" — the realistic "Docker present, buildx missing" case is never covered, and neither is the abort behavior I flagged on ventis/cli.py lines 332-358.

Consider a side_effect keyed on probe_cmd.

🧪 Suggested probe-aware fake
-    def _run_build(
-        self, project_dir, agent_yaml_paths, buildx_available, platform="linux/amd64"
-    ):
+    def _run_build(
+        self,
+        project_dir,
+        agent_yaml_paths,
+        buildx_available,
+        docker_available=True,
+        platform="linux/amd64",
+    ):
-            patch("ventis.cli._docker_available", return_value=buildx_available),
+            patch(
+                "ventis.cli._docker_available",
+                side_effect=lambda probe_cmd=("docker", "info"): (
+                    buildx_available
+                    if "buildx" in probe_cmd
+                    else docker_available
+                ),
+            ),
🤖 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 `@tests/test_cli.py` at line 130, Update the cmd_build test mock for
ventis.cli._docker_available to use a probe-aware side_effect keyed by
probe_cmd, returning Docker availability for “docker info” and an independently
configured buildx result for “docker buildx version”. Add coverage for Docker
present with buildx missing, including the expected abort behavior, while
preserving coverage for Docker entirely absent.
🤖 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 `@ventis/cli.py`:
- Around line 332-358: The Docker availability flow in cmd_build must
distinguish Docker absence from buildx absence: update ventis/cli.py lines
332-358 to guard Docker availability separately with an accurate no-Docker
message, then nest the buildx probe so it selects bake when available or
sequential docker build otherwise. Update the test double at tests/test_cli.py
lines 130-130 to use a side_effect that inspects probe_cmd, and add coverage for
Docker present with buildx missing.
- Around line 88-101: The bake target construction around target["name"] must
normalize names into Buildx-safe slugs containing only letters, digits,
underscores, or hyphens, and enforce uniqueness after normalization. Update the
target-generation logic that derives names from agent_name.lower() to sanitize
spaces, dots, and other invalid characters, then validate normalized names are
unique before adding targets so collisions fail explicitly instead of
overwriting dictionary entries.

---

Nitpick comments:
In @.gitignore:
- Line 43: Update the .gitignore entry for uv.lock so the lock file is no longer
ignored, allowing it to be committed and used for reproducible dependency
resolution.

In `@tests/test_cli.py`:
- Around line 240-270: Strengthen the assertions in
test_build_with_no_agents_builds_nothing and
test_build_skips_agent_without_entrypoint to require docker_calls exactly
matches the expected protoc invocation, rather than merely containing no Docker
call. Preserve the existing no-op build behavior while ensuring unexpected or
missing recorded calls fail these tests.
- Line 130: Update the cmd_build test mock for ventis.cli._docker_available to
use a probe-aware side_effect keyed by probe_cmd, returning Docker availability
for “docker info” and an independently configured buildx result for “docker
buildx version”. Add coverage for Docker present with buildx missing, including
the expected abort behavior, while preserving coverage for Docker entirely
absent.

In `@ventis/cli.py`:
- Around line 321-327: Initialize docker_context to None at the start of each
loop iteration and restructure the branch-specific flow so bake_targets.append
executes only within the branch that successfully assigns a valid context.
Preserve all existing continue paths for missing workflow files, entrypoints, or
matching YAML.
- Around line 248-250: Correct the step numbering in the surrounding CLI
workflow comments so the sequence is consecutive, adding or restoring Step 3
before the existing Step 4 section near bake_targets and updating subsequent
labels as needed.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 525a1dc0-3f5f-4e6d-a407-2f96c59745de

📥 Commits

Reviewing files that changed from the base of the PR and between 4ead684 and 53911f2.

📒 Files selected for processing (6)
  • .dockerignore
  • .gitignore
  • README.md
  • tests/test_cli.py
  • ventis/cli.py
  • ventis/stub_generator.py

Comment thread ventis/cli.py
Comment on lines +88 to +101
bake_config = {
"target": {
target["name"]: {
"context": os.path.abspath(target["context"]),
"dockerfile": "Dockerfile",
"tags": [target["image_name"]],
"platforms": [platform],
"output": ["type=docker"],
# type=docker could be changed to tarring it up, which would be
# faster but skipped because that change would alter ventis deploy
}
for target in bake_targets
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

docker buildx bake target name allowed characters validation

💡 Result:

Docker Buildx Bake targets are strictly validated to ensure compatibility across various systems and naming conventions [1]. The allowed characters for a target name are defined by the regular expression [a-zA-Z0-9_-]+ [2][1]. This means a target name must consist only of: - Uppercase and lowercase letters (a-z, A-Z) - Digits (0-9) - Underscores (_) - Hyphens (-) If a target name includes characters outside of this set—such as dots (.)—docker buildx bake will return an error stating that only those specific characters are allowed [1][3]. In contexts like Docker Compose, where service names might include characters (like dots) that are valid in the Compose specification but invalid for Bake targets, the tooling performs a sanitization step [3][4]. This often involves replacing restricted characters with underscores (e.g., converting service.name to service_name) to ensure they can be processed as Bake targets [2][4]. When working with matrix strategies that dynamically generate names, you can use the sanitize() function within your HCL configuration to ensure generated names comply with these requirements [5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files matching cli.py:\n'
fd -a 'cli\.py$' . || true

printf '\nVentis cli.py outline/snippet:\n'
if [ -f ventis/cli.py ]; then
  wc -l ventis/cli.py
  sed -n '300,360p' ventis/cli.py
  sed -n '70,110p' ventis/cli.py
else
  echo "ventis/cli.py not found"
fi

printf '\nSearch agent_name and bake target usages:\n'
rg -n 'agent_name|target\["name"\]|target_names|bake_target|image_name' ventis -S

Repository: CanyonCodeCoreAI/canyoncodecore

Length of output: 12162


Sanitize bake target names and enforce uniqueness.

target["name"] is built directly from agent_name.lower(), while Buildx target names are limited to [A-Za-z0-9_-]; names with spaces or dots will make the generated bake file fail. Case-only differences also become duplicate dict keys, silently dropping one target from the build command path. Normalize to a safe slug and assert that normalized target names are unique before appending targets.

🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 101-101: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(bake_file_path, "w")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

🤖 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 `@ventis/cli.py` around lines 88 - 101, The bake target construction around
target["name"] must normalize names into Buildx-safe slugs containing only
letters, digits, underscores, or hyphens, and enforce uniqueness after
normalization. Update the target-generation logic that derives names from
agent_name.lower() to sanitize spaces, dots, and other invalid characters, then
validate normalized names are unique before adding targets so collisions fail
explicitly instead of overwriting dictionary entries.

Comment thread ventis/cli.py
Comment on lines +332 to 358
if not bake_targets:
logger.info("No Docker images to build.")
elif _docker_available() and _docker_available(("docker", "buildx", "version")):
docker_container_dir = os.path.join(project_dir, "docker_container")
os.makedirs(docker_container_dir, exist_ok=True)
bake_file_path = os.path.join(docker_container_dir, "docker-bake.json")
_write_bake_file(bake_targets, bake_file_path, _docker_platform())

target_names = [target["name"] for target in bake_targets]
logger.info(
"Building %d Docker image(s) via `docker buildx bake`.",
len(bake_targets),
)
subprocess.run(
["docker", "buildx", "bake", "--file", bake_file_path, *target_names],
check=True,
)
else:
logger.info(
"docker buildx unavailable; falling back to sequential `docker build`."
)
for target in bake_targets:
logger.info("Building Docker image: %s", target["image_name"])
subprocess.run(
_docker_build_cmd("-t", image_name, docker_context), check=True
_docker_build_cmd("-t", target["image_name"], target["context"]),
check=True,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

The two _docker_available probes are collapsed into one condition in both the build logic and the test double. cmd_build distinguishes "Docker present" from "buildx present" only inside a single and, so the else branch cannot tell them apart — and the test mock returns one flat value for both probes, so the divergence is never exercised.

  • ventis/cli.py#L332-L358: split the elif into a separate _docker_available() guard that skips builds with an accurate message, and a nested buildx check that chooses bake vs sequential docker build.
  • tests/test_cli.py#L130-L130: replace the flat return_value with a side_effect that inspects probe_cmd, and add a case covering Docker present with buildx missing.
🧰 Tools
🪛 ast-grep (0.44.1)

[error] 354-357: Use of unsanitized data to create processes
Context: subprocess.run(
_docker_build_cmd("-t", target["image_name"], target["context"]),
check=True,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(os-system-unsanitized-data)


[error] 344-347: Command coming from incoming request
Context: subprocess.run(
["docker", "buildx", "bake", "--file", bake_file_path, *target_names],
check=True,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 354-357: Command coming from incoming request
Context: subprocess.run(
_docker_build_cmd("-t", target["image_name"], target["context"]),
check=True,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

📍 Affects 2 files
  • ventis/cli.py#L332-L358 (this comment)
  • tests/test_cli.py#L130-L130
🤖 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 `@ventis/cli.py` around lines 332 - 358, The Docker availability flow in
cmd_build must distinguish Docker absence from buildx absence: update
ventis/cli.py lines 332-358 to guard Docker availability separately with an
accurate no-Docker message, then nest the buildx probe so it selects bake when
available or sequential docker build otherwise. Update the test double at
tests/test_cli.py lines 130-130 to use a side_effect that inspects probe_cmd,
and add coverage for Docker present with buildx missing.

@iidsample iidsample left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One comment about bake config, let me know what you think

Comment thread ventis/cli.py
for target in bake_targets
}
}
with open(bake_file_path, "w") as f:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is the point of this bake config and what does it do ? How is it configured.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants