Skip to content

Improve rust image upgrades and built-in browser tooling#253

Open
lroolle wants to merge 3 commits intomainfrom
fix/upgrade-mounts
Open

Improve rust image upgrades and built-in browser tooling#253
lroolle wants to merge 3 commits intomainfrom
fix/upgrade-mounts

Conversation

@lroolle
Copy link
Copy Markdown
Member

@lroolle lroolle commented Apr 13, 2026

Summary

  • harden shared .agents mount handling and the versions-up upgrade path
  • rebuild the Rust image with bubblewrap, Node 24 LTS, Go 1.26.2, Playwright CLI/MCP, in-image Playwright browsers, and google-chrome-stable on amd64
  • add a real core image path so Rust, nightly, and release builds reuse stable layers and keep agent upgrades cheap
  • update CI, release/nightly workflows, and user docs for the new image layout

Verification

  • bash tests/version-upgrade.sh
  • built deva-local:core-test and deva-local:rust-test
  • smoke-checked bubblewrap, Rust, Go 1.26.2, Playwright 1.59.1, Playwright MCP, installed browser inventory, and agent CLIs inside deva-local:rust-test
  • confirmed google-chrome is intentionally absent on arm64 and present only on amd64

lroolle added 3 commits April 1, 2026 21:25
- pass resolved tool versions into rust image builds and cover it in CI
- normalize .agents mount targets so overrides and container reuse work
Copilot AI review requested due to automatic review settings April 13, 2026 03:17
@claude-yolo
Copy link
Copy Markdown
Contributor

claude-yolo bot commented Apr 13, 2026

Claude finished @lroolle's task in 2m 59s —— View job


🔴 CRITICAL SECURITY AUDIT FINDINGS - BLOCKING MERGE

Paranoid security audit of PR #253 reveals CRITICAL security vulnerabilities requiring immediate remediation.

Security Model: Container IS the sandbox. Real risks are host bridges: mounted paths, auth files, docker socket, host-net, tmux bridge.

🚨 BLOCKING ISSUES (MUST FIX BEFORE MERGE):

1. BROWSER ATTACK SURFACE EXPLOSION 🔴🔴🔴

  • CRITICAL: Adds Playwright + Chrome + automated browsers to containers
  • RISK: Browsers = massive RCE attack surface with frequent 0-days
  • EXPOSURE: Chrome runs as deva user → browser compromise = full container access
  • MISSING: No browser process isolation/sandboxing within container
  • IMPACT: Single browser vuln can escape to container, then potentially host via mounted paths

2. POTENTIAL SHELL INJECTION IN BROWSER INSTALL 🔴

File: scripts/install-browser-tooling.sh:16

"$DEVA_HOME/.npm-global/bin/playwright" install --with-deps chromium firefox webkit
  • RISK: Unvalidated $DEVA_HOME expansion in shell context
  • ATTACK: If DEVA_HOME contains shell metacharacters → command injection
  • STATUS: Environment validation exists but insufficient for shell safety

3. MOUNT HANDLING PATH TRAVERSAL RISK 🔴

File: deva.sh:430-450 - New .agents mount logic

normalize_container_bind_target() {
    local path="$1"
    while [ "$path" != "/" ] && [[ "$path" == */ ]]; do
        path="${path%/}"
    done
    printf '%s' "$path"
}
  • RISK: Path normalization insufficient for security
  • MISSING: No validation against ../ traversal attempts
  • EXPOSURE: Could mount unintended host paths

⚠️ HIGH-RISK FINDINGS:

4. BUBBLEWRAP SANDBOX BYPASS POTENTIAL 🟠

  • ADDED: bubblewrap package to base image
  • UNKNOWN: No evidence of actual sandboxing configuration
  • RISK: Having sandbox tools without proper config = false security
  • REQUIRED: Verify bubblewrap is actively isolating browser processes

5. PRIVILEGED HOST BRIDGE EXPANSION 🟠

File: scripts/deva-bridge-tmux:12

# SECURITY WARNING:
#   This is a PRIVILEGED HOST BRIDGE. Container gains full tmux control.
#   Effectively a sandbox escape - container can run commands on host.
  • DOCUMENTED RISK: Tmux bridge = explicit sandbox escape
  • EXPANSION: Adding more tooling that could use this bridge

6. CI/WORKFLOW SUPPLY CHAIN RISKS 🟠

  • NEW IMAGES: Core/rust build dependencies change supply chain
  • EXTERNAL DEPS: Browser downloads from external sources
  • MISSING: Checksum verification for browser binaries

🔥 REQUIRED BEFORE MERGE:

MANDATORY SECURITY FIXES:

  1. Browser Process Isolation: Implement bubblewrap sandboxing for all browser processes
  2. Shell Injection Prevention: Properly quote all variable expansions in install scripts
  3. Mount Path Validation: Add traversal protection to mount normalization
  4. Supply Chain Security: Add checksum/signature verification for browser downloads
  5. Attack Surface Documentation: Update docs with new security boundaries

REQUIRED SECURITY TESTS:

  1. Test browser isolation under bubblewrap
  2. Verify mount path traversal protection
  3. Test shell injection resistance in install scripts
  4. Validate browser binary integrity checks

BLOCKING QUESTIONS:

  1. Why add browsers without proper sandboxing? This massively expands attack surface
  2. Where is bubblewrap configuration? Having the tool ≠ using it
  3. How are browser binaries verified? Supply chain integrity?

🚨 RECOMMENDATION: DO NOT MERGE until security fixes implemented

This PR significantly degrades security posture by adding major attack surfaces without corresponding protections.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 946efa83de

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +446 to +450
[ "$QUICK_MODE" = false ] || return 0
[ -d "$HOME/.agents" ] || return 0

if ! user_volume_mounts_target "$target"; then
USER_VOLUMES+=("$HOME/.agents:$target")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Honor --config-home isolation before mounting ~/.agents

This mount is added whenever -Q is not set, but it does not check whether the user passed an explicit --config-home. In that mode the script elsewhere explicitly avoids host config/cache mounts to preserve isolation (see the CONFIG_HOME_FROM_CLI gate later), so auto-mounting $HOME/.agents reintroduces host state and can leak credentials into what users expect to be an isolated auth context. Please gate this mount behind CONFIG_HOME_FROM_CLI=false (or equivalent) so explicit config homes stay isolated.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the deva image build pipeline to introduce a stable core image layer, improve Rust image rebuild efficiency, and bake in browser tooling (Playwright + browsers, plus Chrome on amd64), while updating CI/workflows and documentation to match.

Changes:

  • Add a core image build path and update versions-up/Make targets to build core first and base Rust on it.
  • Rebuild images with updated runtimes/tooling (Node 24, Go version arg, bubblewrap, Playwright + MCP + in-image browsers, Chrome on amd64).
  • Update CI, release/nightly workflows, and docs; add a test validating version-upgrade.sh docker build args.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/version-upgrade.sh Adds CI test harness to validate scripts/version-upgrade.sh docker build invocations/args.
scripts/version-upgrade.sh Builds core, then main, then rust; adds args for Go/Playwright versions and uses core as Rust base.
scripts/release-utils.sh Expands changelog printing behavior (removes prior truncation limits).
scripts/install-browser-tooling.sh Installs Playwright CLI + MCP and installs browsers in-image.
scripts/install-agent-tooling.sh Minor change to run atlas install from $DEVA_HOME.
Makefile Adds Go/Playwright variables and new build targets (buildx-multi-core); bases Rust builds on core.
docs/troubleshooting.md Documents bubblewrap requirement for newer Claude Code on Linux.
docs/custom-images.md Updates custom build instructions for new core + Rust layering and browser tooling.
Dockerfile.rust Adds Playwright versions/labels, sets browsers path, installs Playwright + browsers, and installs Chrome on amd64 only.
Dockerfile Adds bubblewrap, bumps Node major to 24, and parameterizes Go install via GO_VERSION.
deva.sh Hardens .agents shared mount behavior and normalizes bind targets for mount comparisons.
.github/workflows/release.yml Adds/publishes core image, updates Node version, and wires Rust builds to use *-core base.
.github/workflows/nightly-images.yml Adds nightly core image publishing and updates Rust to use nightly *-core base; updates Node version.
.github/workflows/ci.yml Adds version-upgrade build-args test and rust/browser tooling smoke checks; updates Node version.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 10 to 14
# Defaults
CHECK_IMAGE=${MAIN_IMAGE:-ghcr.io/thevibeworks/deva:latest}
BUILD_IMAGE=${BUILD_IMAGE:-ghcr.io/thevibeworks/deva:latest}
CORE_IMAGE=${CORE_IMAGE:-ghcr.io/thevibeworks/deva:core}
RUST_IMAGE=${RUST_IMAGE:-ghcr.io/thevibeworks/deva:rust}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

CHECK_IMAGE is initialized from MAIN_IMAGE, so there is no way to override the inspected image via a CHECK_IMAGE env var even though the internal variable is named CHECK_IMAGE. Consider either renaming the env var in the script/usage to CHECK_IMAGE, or adding CHECK_IMAGE as an accepted override (e.g., CHECK_IMAGE=${CHECK_IMAGE:-${MAIN_IMAGE:-...}}) to avoid confusion and keep tests/CI consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +259 to 263
for v, ver, body in sorted(changes, key=lambda x: x[0], reverse=True):
print(f"{ver}")
if body:
for line in [l.rstrip() for l in body.split("\n") if l.strip()][:15]:
for line in [l.rstrip() for l in body.split("\n") if l.strip()]:
print(f" {line}")
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

This loop now prints all GitHub release bodies between current and latest, without any line/entry limits. For repos with long release notes, this can bloat output and increase runtime. Consider reintroducing a default limit (e.g., top N releases and first M lines), with an env var to opt into full output when needed.

Copilot uses AI. Check for mistakes.
Comment on lines 468 to 472
lines = section.strip().split("\n")
print(lines[0].replace("## ", ""))
for line in [l for l in lines[1:] if l.strip()][:8]:
for line in [l for l in lines[1:] if l.strip()]:
print(line)
print()
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

fetch_recent_markdown_changelog is still limited by count, but each section now prints all content lines. Some changelog sections can be extremely long and overwhelm make versions/CI logs. Consider keeping a per-section line cap (or making it configurable) to keep the "recent" view concise.

Copilot uses AI. Check for mistakes.
Comment on lines 497 to 501
body = (rel.get("body") or "").replace("\r\n", "\n").strip()
print(ver)
if body:
for line in [l.rstrip() for l in body.split("\n") if l.strip()][:12]:
for line in [l.rstrip() for l in body.split("\n") if l.strip()]:
print(f" {line}")
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

fetch_recent_github_releases now prints the full release body (all non-empty lines). Even with per_page=$count, individual release notes can be large and dominate output. Consider restoring the previous line cap (or making it configurable) so the "recent" view stays readable.

Copilot uses AI. Check for mistakes.
PATH="$FAKE_BIN:$PATH" \
DOCKER_BUILD_LOG="$DOCKER_BUILD_LOG" \
AUTO_YES=1 \
CHECK_IMAGE="ghcr.io/thevibeworks/deva:rust" \
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

The test sets CHECK_IMAGE, but scripts/version-upgrade.sh does not read CHECK_IMAGE from the environment (it derives CHECK_IMAGE from MAIN_IMAGE). This makes the test misleading and could mask regressions around which image is inspected. Set MAIN_IMAGE here instead, or update version-upgrade.sh to accept CHECK_IMAGE as an explicit override.

Suggested change
CHECK_IMAGE="ghcr.io/thevibeworks/deva:rust" \
MAIN_IMAGE="ghcr.io/thevibeworks/deva:rust" \

Copilot uses AI. Check for mistakes.
Comment on lines +212 to 214
for change in reversed(changes):
print(change)
print()
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

This now prints all matching changelog sections between current and latest versions (previously capped to the most recent few). That can produce very large CI logs and slow runs when upgrades span many versions. Consider restoring a default cap (with an env override for full output) to keep output bounded.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants