Skip to content

refactor(box-images)!: adopt v0.1.0 line, relocate under apps/ - #1100

Merged
DorianZheng merged 4 commits into
mainfrom
refactor/box-images-layout-release
Jul 31, 2026
Merged

refactor(box-images)!: adopt v0.1.0 line, relocate under apps/#1100
DorianZheng merged 4 commits into
mainfrom
refactor/box-images-layout-release

Conversation

@DorianZheng

@DorianZheng DorianZheng commented Jul 31, 2026

Copy link
Copy Markdown
Member

Points every curated-image reference at the v0.1.0 tag, gives the box images a
home matching the rest of the repo, and splits their build from their release.

Images

All 53 references move from 20260605-p0-r3 to v0.1.0 across 41 files. The two
tags are different image lineages, not two versions of one:

20260605-p0-r3 v0.1.0
daemon COPY .../boxlite-daemon absent
entrypoint /boxlite/bin/start-agent-runtime none (node keeps stock docker-entrypoint.sh)
user root boxlite
arch linux/amd64 only amd64 + arm64

Because v0.1.0 runs unprivileged, the six e2e files that wrote to /root now use
/workspace — still on the container rootfs, so copy_out sees it, and owned by
the box user.

Layout

images/agent-runtime/apps/box-images/, joining apps/{api,dex,proxy,runner},
which already co-locate their Dockerfiles; top-level images/ is gone.
scripts/images/build-agent-runtime.shapps/box-images/build.sh so the
Dockerfiles, VERSION and builder sit together. "agent-runtime" was ambiguous next
to src/guest (the guest agent) and apps/runner.

Workflows

  • build-box-images.yml (was publish-boxlite-cloud-images.yml) validates only —
    both architectures at PUSH=0, contents: read, no registry login, so it cannot
    write to GHCR.
  • release-box-images.yml is the sole publisher, driven by an
    apps/box-images/vMAJOR.MINOR.PATCH tag (same convention as the existing
    sdks/go/v* tags) and restricted to a release tag or main.

Previously any edit under the image directory republished the same tag, silently
moving the bytes a running box pulls. The release path now rejects a tag that
disagrees with VERSION and refuses to republish an existing version unless
dispatched with allow-overwrite. The existence check reads the registry API and
branches on HTTP status — only 404 counts as free, so a 5xx or an expired token
stops the release instead of reading as "not published".

Verification

  • actionlint clean on both workflows.
  • build.sh builds all three flavors from its new location; the resulting arm64
    image IDs match the pre-move builds, and the Dockerfiles are byte-identical
    renames.
  • curated-images.constant.spec.ts passes 9/9.
  • Release-workflow shell was exercised by extracting the run: bodies from the YAML
    and driving them directly: version resolution 10/10 (tag/VERSION disagreement,
    missing or wrong tag prefix, prerelease, malformed input) and the overwrite guard
    8/8 across 404 / 200 / 500 / 429 / 401 / token-exchange failure / empty token /
    allow-overwrite.

The e2e suite has not been run against the new images. The /root/workspace
move is derived from the image config — images/config.rs:166 reads the OCI user and
portal/interfaces/container.rs:131 passes it through — not from an observed run.

Notes for review

  • This branch is behind main and conflicts with 2933c30bd fix(infra): harden SST deployments (#1093) in apps/infra/.env.example. Needs a rebase before merge;
    the resolution must keep v0.1.0.
  • Follow-up, not fixed here: Record published digests runs imagetools inspect
    under set -e, so a flaky inspect reddens the job after a successful publish. No
    silent-damage path — re-running the release hits the overwrite guard.

https://claude.ai/code/session_01T3B2RsTupPrn2gPtHymU5T

Summary by CodeRabbit

  • New Features

    • Introduced versioned Box images (v0.1.0) for Base, Python, and Node.js environments.
    • Added AMD64 and ARM64 image support.
    • Added controlled image publishing with version validation and registry safeguards.
  • Bug Fixes

    • Updated quickstarts, default configurations, and tests to use versioned images.
    • Standardized container file operations under /workspace.
  • Documentation

    • Documented image validation and release workflows, including non-publishing builds for main-branch changes.

Point every curated-image reference at the v0.1.0 tag and give the
images a home and a release pipeline matching the rest of the repo.

Images
- All 53 refs move from 20260605-p0-r3 to v0.1.0, across 41 files.
- v0.1.0 is multi-arch (linux/amd64 + linux/arm64); the old tag was
  amd64-only.
- v0.1.0 runs as USER boxlite, so the six e2e files that wrote to /root
  now use /workspace, which is on the container rootfs (not tmpfs, so
  copy_out still sees it) and is owned by the box user.

Layout
- images/agent-runtime/ -> apps/box-images/, joining apps/{api,dex,
  proxy,runner}, which already co-locate their Dockerfiles. Top-level
  images/ is removed.
- scripts/images/build-agent-runtime.sh -> apps/box-images/build.sh, so
  the Dockerfiles, VERSION and builder live together; the script anchors
  on its own directory and keeps the repo root as the build context.
- "agent-runtime" was ambiguous next to src/guest (the guest agent) and
  apps/runner; "box-images" says what they are.

Workflows
- build-box-images.yml (was publish-boxlite-cloud-images.yml) validates
  only: both architectures with PUSH=0, contents:read, no registry
  login, so it cannot write to GHCR.
- release-box-images.yml is the sole publisher, driven by an
  apps/box-images/vMAJOR.MINOR.PATCH tag, matching the existing
  sdks/go/v* convention. It rejects a tag disagreeing with
  apps/box-images/VERSION, and refuses to republish a version already on
  GHCR unless dispatched with allow-overwrite. Previously any edit under
  the image directory republished the same tag, silently moving bytes a
  running box pulls.
- The existence check reads the registry API and branches on the HTTP
  status; only 404 counts as free, so a 5xx or an expired token stops
  the release rather than reading as "not published".
- Publishing stays restricted to a release tag or main, preserving the
  guard the replaced workflow carried.

BREAKING CHANGE: v0.1.0 images carry no in-box daemon and no
/boxlite/bin/start-agent-runtime entrypoint, and run as USER boxlite
rather than root. Boxes booted from the curated refs lose the daemon on
PID 1 port 2280. Nothing in-repo consumes it, and the e2e suite has not
been run against the new images.
@DorianZheng
DorianZheng requested a review from a team as a code owner July 31, 2026 01:36
@boxlite-agent

boxlite-agent Bot commented Jul 31, 2026

Copy link
Copy Markdown

📦 BoxLite review — looks good · 67a064b

Review evidence

  • git diff --numstat origin/main...HEAD && git diff origin/main...HEAD — ~90 files, mostly box-images rename + version bump v0.1.0
  • python3 -m unittest discover -s scripts/test/e2e/lib -p 'test_*.py' -v — 4/4 image-resolution tests pass
  • bash -n apps/box-images/build.sh — syntax valid
  • npx vitest run apps/api/src/box/constants/curated-images.constant.spec.ts — node_modules not installed; change is trivial string-literal bump
  • grep -rn old image tag/paths across repo — no stale 20260605-p0-r3 or images/agent-runtime refs remain

Risk notes

  • release-box-images.yml GHCR overwrite guard — reviewed tag-vs-VERSION check, HTTP-status branching (only 404=free), allow-overwrite gate — logic sound, no trigger for accidental publish since push:tags only + workflow_dispatch
  • build.sh version/platform validation — regex-validated TAG and PLATFORMS, syntax-checked; --load vs --output=cacheonly branching correct for local vs CI
  • e2e image resolution (run.sh + lib/images.py) — unit tests cover missing VERSION, empty resolver, override, and success paths; all pass
  • sampled only — did not deeply inspect the ~40 mechanical 1-2 line e2e test/SDK files (test_.py, e2e_.go/ts/c) beyond spot checks — all appear to be identical sys.path/import/tag-bump mechanical edits per grep sweep
  • dashboard/quickstart template files — 1-line changes each, not inspected individually — consistent with version-string bump pattern seen elsewhere
.github/workflows/release-box-images.yml
  release job  +172/-0  new GHCR publish workflow
.github/workflows/build-box-images.yml
  build job  +48/-0  new PR validation workflow
.github/workflows/publish-boxlite-cloud-images.yml
  +0/-77  old publish workflow deleted
apps/box-images/build.sh
  build_image/normalize_tag  +4/-3(rename)  moved+tweaked from scripts/images
scripts/test/e2e/lib/images.py
  base_image_ref/default_image  +31/-0  new VERSION-backed image resolver
scripts/test/e2e/lib/test_images.py
  ImageResolutionTest  +113/-0  new unit tests, verified passing
scripts/test/e2e/run.sh
  image resolution + unittest step  +33/-17  adds curated-image export step
apps/api/src/box/constants/curated-images.constant.ts
  BUILTIN_IMAGE_SOURCES  +3/-3  fallback refs bumped to v0.1.0
apps/infra/sst.config.ts
  BOXLITE_SYSTEM_*_IMAGE  +4/-4  env defaults bumped to v0.1.0
1 finding summary
  • 🧹 apps/infra/sst.config.ts:478 comment says digest-pinned but value is a tag — comment calls BOXLITE_SYSTEM_*_IMAGE refs 'digest-pinned' but the value is mutable tag v0.1.0, not a sha256 digest — misleading if someone relies on the comment for rollout safety

reviewed 67a064b in a BoxLite microVM · @boxlite-agent review to re-run · powered by BoxLite

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b159adb-1507-492c-95e7-5a88408e7403

📥 Commits

Reviewing files that changed from the base of the PR and between b6880b2 and 67a064b.

📒 Files selected for processing (3)
  • .github/workflows/README.md
  • apps/infra/.env.example
  • apps/infra/sst.config.ts

📝 Walkthrough

Walkthrough

Introduces v0.1.0 Base, Python, and Node images with separate validation and release workflows. Updates application, infrastructure, quickstart, E2E, benchmark, and stress-test defaults to use versioned multi-architecture images and /workspace.

Changes

Box image release

Layer / File(s) Summary
Image definitions and build paths
apps/box-images/*, apps/scripts/local-dex-env.mjs
Adds versioned Base, Python, and Node images with /workspace, unprivileged boxlite execution, and updated build paths.
Validation and release workflows
.github/workflows/*
Separates non-publishing validation from controlled GHCR publication with version checks, overwrite protection, manifest checks, and digest reporting.
Runtime and application references
apps/api/..., apps/dashboard/..., apps/infra/..., apps/infra-local/...
Replaces dated image tags with v0.1.0 across curated defaults, quickstarts, infrastructure configuration, and local runtime documentation.
E2E image resolution and defaults
scripts/test/e2e/lib/*, scripts/test/e2e/run.sh, scripts/test/e2e/cases/*, scripts/test/e2e/sdks/*, scripts/test/image.js, scripts/test/stress/*
Centralizes image resolution, validates setup before bootstrap, and updates SDK and stress-test defaults.
E2E workspace paths
scripts/test/e2e/cases/*, scripts/test/e2e/sdks/node/*
Moves guest filesystem operations from /root to /workspace.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant VERSION
  participant GHCR
  participant Buildx
  GitHubActions->>VERSION: resolve and validate image version
  GitHubActions->>GHCR: check existing manifests
  GitHubActions->>GHCR: authenticate
  GitHubActions->>Buildx: build and publish amd64 and arm64 images
  Buildx->>GHCR: push image manifests
  GitHubActions->>GHCR: inspect published digests
Loading

Possibly related PRs

Suggested reviewers: ltstriker

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the image version change, repository relocation, and breaking nature of the refactor.
Description check ✅ Passed The description covers the summary, changes, verification steps, risks, testing gaps, and rollout details with relevant technical context.
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 refactor/box-images-layout-release

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.

Comment on lines +36 to +37
"dd if=/dev/urandom of=/workspace/big4m bs=4096 count=1024 2>/dev/null "
"&& sha256sum /workspace/big4m"],
Comment on lines +66 to +67
"dd if=/dev/urandom of=/workspace/blob bs=4096 count=64 2>/dev/null "
"&& sha256sum /workspace/blob && sync"], None,
Comment on lines +58 to +63
'cat > /workspace/greet.sh << \'EOF\'\n'
'#!/bin/sh\n'
'NAME="${1:-World}"\n'
'echo "Hello, ${NAME}! Today is $(date +%A)."\n'
'EOF\n'
'chmod +x /root/greet.sh'],
'chmod +x /workspace/greet.sh'],
Comment on lines +179 to +180
"tr '[:lower:]' '[:upper:]' < /workspace/input.txt > /workspace/upper.txt && "
"wc -w < /workspace/input.txt | tr -d ' ' > /workspace/count.txt"],
Comment on lines +285 to +287
"echo secret > /workspace/private.txt && chmod 600 /workspace/private.txt && "
"echo public > /workspace/public.txt && chmod 644 /workspace/public.txt && "
"stat -c '%a %n' /workspace/private.txt /workspace/public.txt"],

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

🧹 Nitpick comments (1)
apps/box-images/node.Dockerfile (1)

24-48: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Node image has no C/C++ toolchain for native module builds.

python3/python3-pip are installed for node-gyp, but there's no build-essential/make/g++. Many common npm packages with native bindings (e.g. bcrypt, sharp, sqlite3) will fail to install without a compiler. python.Dockerfile installs build-essential for the same reason on the Python side; consider parity here. Note that boxlite has passwordless sudo, so users can work around this themselves, which softens the impact.

🔧 Proposed fix
     bash \
+    build-essential \
     ca-certificates \
🤖 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 `@apps/box-images/node.Dockerfile` around lines 24 - 48, Update the package
list in the Node image build step to install the C/C++ compilation toolchain
required by node-gyp and native npm modules, matching the existing build-tooling
setup used by the Python image. Keep the change scoped to the apt-get install
dependencies in the Dockerfile.
🤖 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 @.github/workflows/release-box-images.yml:
- Around line 32-37: Add a suitable timeout-minutes value to the release job
definition identified by release in the workflow, bounding stalled build or push
operations while preserving the existing ref restriction and concurrency
behavior.

---

Nitpick comments:
In `@apps/box-images/node.Dockerfile`:
- Around line 24-48: Update the package list in the Node image build step to
install the C/C++ compilation toolchain required by node-gyp and native npm
modules, matching the existing build-tooling setup used by the Python image.
Keep the change scoped to the apt-get install dependencies in the Dockerfile.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1e3e890b-4c56-4326-bfee-b0cb0a18588a

📥 Commits

Reviewing files that changed from the base of the PR and between 2cfa91f and 6bffae3.

📒 Files selected for processing (58)
  • .github/workflows/README.md
  • .github/workflows/build-box-images.yml
  • .github/workflows/publish-boxlite-cloud-images.yml
  • .github/workflows/release-box-images.yml
  • apps/api/src/box/constants/curated-images.constant.spec.ts
  • apps/api/src/box/constants/curated-images.constant.ts
  • apps/box-images/VERSION
  • apps/box-images/base.Dockerfile
  • apps/box-images/build.sh
  • apps/box-images/node.Dockerfile
  • apps/box-images/python.Dockerfile
  • apps/dashboard/src/components/Box/CreateBoxDialog.tsx
  • apps/dashboard/src/lib/quickstart/interfaces.json
  • apps/dashboard/src/lib/quickstart/templates/c.c
  • apps/dashboard/src/lib/quickstart/templates/cli.sh
  • apps/dashboard/src/lib/quickstart/templates/go.go
  • apps/dashboard/src/lib/quickstart/templates/python.py
  • apps/dashboard/src/lib/quickstart/templates/rest.sh
  • apps/dashboard/src/lib/quickstart/templates/rust.rs
  • apps/dashboard/src/lib/quickstart/templates/typescript.mts
  • apps/infra-local/compose/_local_arm64.py
  • apps/infra-local/compose/native.py
  • apps/infra/.env.example
  • apps/infra/sst.config.ts
  • apps/scripts/local-dex-env.mjs
  • scripts/test/e2e/README.md
  • scripts/test/e2e/bench_rest_startup.py
  • scripts/test/e2e/cases/conftest.py
  • scripts/test/e2e/cases/test_c_coverage.py
  • scripts/test/e2e/cases/test_c_entry.py
  • scripts/test/e2e/cases/test_cli_comprehensive.py
  • scripts/test/e2e/cases/test_cli_detach_recovery.py
  • scripts/test/e2e/cases/test_cli_entry.py
  • scripts/test/e2e/cases/test_exec_comprehensive.py
  • scripts/test/e2e/cases/test_files_comprehensive.py
  • scripts/test/e2e/cases/test_files_io.py
  • scripts/test/e2e/cases/test_go_coverage.py
  • scripts/test/e2e/cases/test_go_entry.py
  • scripts/test/e2e/cases/test_lifecycle_comprehensive.py
  • scripts/test/e2e/cases/test_node_comprehensive.py
  • scripts/test/e2e/cases/test_node_coverage.py
  • scripts/test/e2e/cases/test_node_entry.py
  • scripts/test/e2e/cases/test_node_tunnel.py
  • scripts/test/e2e/cases/test_real_world.py
  • scripts/test/e2e/fixture_setup.py
  • scripts/test/e2e/sdks/c/e2e_basic.c
  • scripts/test/e2e/sdks/c/e2e_exec.c
  • scripts/test/e2e/sdks/go/e2e_basic.go
  • scripts/test/e2e/sdks/go/e2e_copy.go
  • scripts/test/e2e/sdks/go/e2e_exec_options.go
  • scripts/test/e2e/sdks/node/e2e_basic.ts
  • scripts/test/e2e/sdks/node/e2e_comprehensive.ts
  • scripts/test/e2e/sdks/node/e2e_copy.ts
  • scripts/test/e2e/sdks/node/e2e_exec.ts
  • scripts/test/e2e/sdks/node/e2e_tunnel.ts
  • scripts/test/stress/README.md
  • scripts/test/stress/api-create-box.k6.js
  • scripts/test/stress/api-vm-lifecycle.k6.js
💤 Files with no reviewable changes (1)
  • .github/workflows/publish-boxlite-cloud-images.yml

Comment on lines +32 to +37
release:
name: Publish box images
runs-on: ubuntu-latest
# The workflow this replaced allowed publishing only from main; workflow_dispatch can target
# any ref, so keep that restriction. A release tag is the other legitimate source.
if: github.ref_type == 'tag' || github.ref == 'refs/heads/main'

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

Add timeout-minutes to bound a stuck release.

This job has no explicit timeout, so it inherits GitHub's 360-minute default. Combined with concurrency: { group: release-box-images, cancel-in-progress: false } (repo-wide, serialized), a hung build/push step (e.g. a stalled registry push or retry loop) blocks every subsequent release for up to 6 hours with no automatic recovery.

🔧 Proposed fix
   release:
     name: Publish box images
     runs-on: ubuntu-latest
+    timeout-minutes: 30
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
release:
name: Publish box images
runs-on: ubuntu-latest
# The workflow this replaced allowed publishing only from main; workflow_dispatch can target
# any ref, so keep that restriction. A release tag is the other legitimate source.
if: github.ref_type == 'tag' || github.ref == 'refs/heads/main'
release:
name: Publish box images
runs-on: ubuntu-latest
timeout-minutes: 30
# The workflow this replaced allowed publishing only from main; workflow_dispatch can target
# any ref, so keep that restriction. A release tag is the other legitimate source.
if: github.ref_type == 'tag' || github.ref == 'refs/heads/main'
🤖 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 @.github/workflows/release-box-images.yml around lines 32 - 37, Add a
suitable timeout-minutes value to the release job definition identified by
release in the workflow, bounding stalled build or push operations while
preserving the existing ref restriction and concurrency behavior.

The curated base ref was written out 31 times under scripts/test/, so a
version bump had to edit every driver. Most driver sites consulted
BOXLITE_E2E_IMAGE first, but no test entrypoint exported it, which made
the fallback the value normal runs used.

run.sh now resolves the ref once from apps/box-images/VERSION and
exports it, so pytest and the Go, C and Node subprocesses it spawns all
agree.

Fallbacks collapse to one place per executable ecosystem:

- lib/images.py reads apps/box-images/VERSION for Python and run.sh.
- image.js is shared by the Node and k6 JavaScript drivers.
- sdks/go/e2e_image.go and sdks/c/e2e_image.h cover binaries compiled to
  /tmp with no reliable path back to the repo.

Go drivers are each their own package main, so the shared constant has
to be named on the build line; test_go_entry and test_go_coverage now
pass it alongside the driver.

Left alone deliberately: apps/api's curated-images constant is already
the single definition; dashboard quickstart templates are sample code
users copy; sst config entries are deploy-time env defaults.

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

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

Inline comments:
In `@scripts/test/e2e/cases/test_go_coverage.py`:
- Around line 26-33: The _build_go function uses predictable shared output paths
that can collide across parallel runs or follow pre-existing symlinks. Create
the binary under a tempfile-created unique directory, ensure the directory is
cleaned up after the test completes, and preserve the existing Go build inputs
and returned Path behavior.

In `@scripts/test/e2e/fixture_setup.py`:
- Line 49: Update SNAPSHOTS_TO_REGISTER and the register_snapshot flow so the
environment-controlled result of default_image() cannot be interpolated into the
psql SQL statement. Validate image references against an appropriate safe format
before registration, or replace the raw psql command construction with a
parameterized database client while preserving cleanup of errored snapshots.

In `@scripts/test/image.js`:
- Around line 1-3: Update the DEFAULT_BOX_IMAGE export in scripts/test/image.js
to be compatible with the repository’s CommonJS package configuration, either by
using CommonJS syntax or by converting the file and its consumers to an
explicitly supported ES-module form. Ensure JavaScript test drivers can import
or require DEFAULT_BOX_IMAGE without needing an implicit module-context
override.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 59daeba7-21d8-4de9-b73c-45279d20d412

📥 Commits

Reviewing files that changed from the base of the PR and between 6bffae3 and 8c7a53c.

📒 Files selected for processing (33)
  • scripts/test/e2e/README.md
  • scripts/test/e2e/bench_rest_startup.py
  • scripts/test/e2e/cases/conftest.py
  • scripts/test/e2e/cases/test_c_coverage.py
  • scripts/test/e2e/cases/test_c_entry.py
  • scripts/test/e2e/cases/test_cli_comprehensive.py
  • scripts/test/e2e/cases/test_cli_detach_recovery.py
  • scripts/test/e2e/cases/test_cli_entry.py
  • scripts/test/e2e/cases/test_go_coverage.py
  • scripts/test/e2e/cases/test_go_entry.py
  • scripts/test/e2e/cases/test_node_comprehensive.py
  • scripts/test/e2e/cases/test_node_coverage.py
  • scripts/test/e2e/cases/test_node_entry.py
  • scripts/test/e2e/cases/test_node_tunnel.py
  • scripts/test/e2e/fixture_setup.py
  • scripts/test/e2e/lib/images.py
  • scripts/test/e2e/run.sh
  • scripts/test/e2e/sdks/c/e2e_basic.c
  • scripts/test/e2e/sdks/c/e2e_exec.c
  • scripts/test/e2e/sdks/c/e2e_image.h
  • scripts/test/e2e/sdks/go/e2e_basic.go
  • scripts/test/e2e/sdks/go/e2e_copy.go
  • scripts/test/e2e/sdks/go/e2e_exec_options.go
  • scripts/test/e2e/sdks/go/e2e_image.go
  • scripts/test/e2e/sdks/node/e2e_basic.ts
  • scripts/test/e2e/sdks/node/e2e_comprehensive.ts
  • scripts/test/e2e/sdks/node/e2e_copy.ts
  • scripts/test/e2e/sdks/node/e2e_exec.ts
  • scripts/test/e2e/sdks/node/e2e_tunnel.ts
  • scripts/test/image.js
  • scripts/test/stress/README.md
  • scripts/test/stress/api-create-box.k6.js
  • scripts/test/stress/api-vm-lifecycle.k6.js
🚧 Files skipped from review as they are similar to previous changes (9)
  • scripts/test/e2e/sdks/c/e2e_basic.c
  • scripts/test/e2e/sdks/node/e2e_exec.ts
  • scripts/test/e2e/cases/conftest.py
  • scripts/test/e2e/sdks/node/e2e_basic.ts
  • scripts/test/stress/README.md
  • scripts/test/e2e/README.md
  • scripts/test/e2e/sdks/node/e2e_comprehensive.ts
  • scripts/test/e2e/cases/test_node_entry.py
  • scripts/test/e2e/sdks/node/e2e_tunnel.ts

Comment on lines 26 to +33
def _build_go(src_name: str) -> Path:
src = DRIVERS / src_name
assert src.exists(), f"{src} missing"
bin_path = Path(f"/tmp/boxlite_e2e_go_{src_name.replace('.go', '')}")
subprocess.run(
["go", "build", "-o", str(bin_path), str(src)],
# Each driver is its own `package main`, so the shared image constant has
# to be named on the build line rather than picked up from the directory.
["go", "build", "-o", str(bin_path), str(DRIVERS / "e2e_image.go"), str(src)],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Use an isolated temporary output path.

_build_go() writes each binary to a predictable /tmp/boxlite_e2e_go_* path. Parallel E2E runs can overwrite another test’s binary. A pre-existing path or symlink can also redirect the build output on a shared runner. Use a tempfile-created directory and clean it up after the test.

🧰 Tools
🪛 ast-grep (0.45.0)

[info] 28-28: Do not hardcode temporary file or directory names
Context: f"/tmp/boxlite_e2e_go_{src_name.replace('.go', '')}"
Note: [CWE-377] Insecure Temporary File.

(hardcoded-tmp-file)

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

In `@scripts/test/e2e/cases/test_go_coverage.py` around lines 26 - 33, The
_build_go function uses predictable shared output paths that can collide across
parallel runs or follow pre-existing symlinks. Create the binary under a
tempfile-created unique directory, ensure the directory is cleaned up after the
test completes, and preserve the existing Go build inputs and returned Path
behavior.

Source: Linters/SAST tools

or "devkey" # only used when bootstrap hasn't run yet
)
SNAPSHOTS_TO_REGISTER = ["ghcr.io/boxlite-ai/boxlite-agent-base:20260605-p0-r3", "ubuntu:22.04", "ubuntu:24.04"]
SNAPSHOTS_TO_REGISTER = [default_image(), "ubuntu:22.04", "ubuntu:24.04"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not interpolate the environment-controlled image into SQL.

default_image() honors BOXLITE_E2E_IMAGE, so this snapshot name can contain arbitrary text. When the snapshot is in an error state, register_snapshot() inserts name into the psql -c statement at Lines 117-118. A quote or semicolon can change the statement and delete unintended data. Validate the image reference, or execute the delete with a parameterized database client.

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

In `@scripts/test/e2e/fixture_setup.py` at line 49, Update SNAPSHOTS_TO_REGISTER
and the register_snapshot flow so the environment-controlled result of
default_image() cannot be interpolated into the psql SQL statement. Validate
image references against an appropriate safe format before registration, or
replace the raw psql command construction with a parameterized database client
while preserving cleanup of errored snapshots.

Comment thread scripts/test/image.js
Comment on lines +1 to +3
// Fallback for JavaScript test drivers run outside scripts/test/e2e/run.sh.
// Keep this in step with apps/box-images/VERSION.
export const DEFAULT_BOX_IMAGE = 'ghcr.io/boxlite-ai/boxlite-agent-base:v0.1.0'

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

🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -HI -t f 'package.json|biome.json|biome.jsonc' . | while IFS= read -r file; do
  echo "== $file =="
  rg -n '"type"\s*:\s*"module"|commonjs|module' "$file" || true
done

rg -n -C 3 'from .*image\.js|DEFAULT_BOX_IMAGE' scripts/test \
  --glob '*.js' --glob '*.ts' || true

Repository: boxlite-ai/boxlite

Length of output: 11411


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package.json type fields and scripts/test references =="
python3 - <<'PY'
import json, pathlib
for p in pathlib.Path('.').rglob('package.json'):
    if 'node_modules' in p.parts:
        continue
    try:
        data = json.loads(p.read_text())
    except Exception:
        continue
    if p.name == 'package.json' and p.parts[:1] == ('.',):
        print(f"== {p} ==")
        print("type:", data.get("type"))
        print("scripts:", {k:data["scripts"].get(k) for k in data.get("scripts", {}) if "test" in k.lower() or "e2e" in k.lower() or "run" in k.lower()})
PY

echo "== locate runner scripts =="
fd -HI -t f 'run\.sh|scripts|test' . | sed 's#^\./##' | head -200

echo "== e2e scripts/package/module related files =="
git ls-files | rg '(^scripts/test|package\.json|biome\.json|README|pnpm|tsconfig|vite|rollup|esbuild)' | sed -n '1,240p'

echo "== specific scripts/test files =="
for f in scripts/test/e2e/run.sh scripts/test/image.js package.json; do
  if [ -f "$f" ]; then
    echo "== $f =="
    sed -n '1,160p' "$f"
  fi
done

Repository: boxlite-ai/boxlite

Length of output: 17690


Make scripts/test/image.js ES-module compatible or CommonJS compatible.

The root package.json is "type": "commonjs", and scripts/test/e2e/run.sh runs only pytest rather than a Node runner that sets module context for scripts/test/image.js. If a JavaScript test driver imports DEFAULT_BOX_IMAGE, add ESMODULE=1 to the node command, use the .mjs extension, or change this export to CommonJS.

🧰 Tools
🪛 Biome (2.5.5)

[error] 3-3: Illegal use of an export declaration outside of a module

(parse)

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

In `@scripts/test/image.js` around lines 1 - 3, Update the DEFAULT_BOX_IMAGE
export in scripts/test/image.js to be compatible with the repository’s CommonJS
package configuration, either by using CommonJS syntax or by converting the file
and its consumers to an explicitly supported ES-module form. Ensure JavaScript
test drivers can import or require DEFAULT_BOX_IMAGE without needing an implicit
module-context override.

Source: Linters/SAST tools

Run fast image-resolution unit tests before bootstrap. The tests execute
copies of the real run.sh and images.py with post-resolution commands
stubbed, so they need neither the Linux VM nor running services.

Cover a missing VERSION file, empty resolver output, a VERSION-derived
default and an explicit override. Record whether the bootstrap check ran
so resolver failures must stop at the intended boundary.
Signed-off-by: dorianzheng <8065637+DorianZheng@users.noreply.github.com>
@DorianZheng
DorianZheng merged commit bad0cbb into main Jul 31, 2026
19 checks passed
@DorianZheng
DorianZheng deleted the refactor/box-images-layout-release branch July 31, 2026 06:43
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.

1 participant