Skip to content

applecontainer: properly wire named volume mounts#67

Merged
bilby91 merged 2 commits into
mainfrom
fix/applecontainer-named-volumes
May 16, 2026
Merged

applecontainer: properly wire named volume mounts#67
bilby91 merged 2 commits into
mainfrom
fix/applecontainer-named-volumes

Conversation

@bilby91
Copy link
Copy Markdown
Member

@bilby91 bilby91 commented May 16, 2026

Summary

  • Bridge's toFilesystem was treating MountType=volume as a virtiofs bind. Apple's apiserver normalizes the source via URL(fileURLWithPath:), which resolves relative paths against the launching process's CWD — yielding paths like /private/tmp/runner/<project>_<vol> that don't exist and surface as errno 2 at VM bootstrap.
  • Fix: call ClientVolume.inspect(name) to fetch the backing image path + filesystem format, then construct a proper Filesystem.volume(...) — same shape apple/container's own CLI emits.
  • Add TestRunContainer_NamedVolume regression guard.

How it was found

Bringing up a compose-source devcontainer (crunchloop/dap) on the applecontainer backend via compose.Orchestrator. The app service's claude-config named volume hit this code path. With the fix, all 7 services started cleanly under apple/container.

Test plan

  • go test ./runtime/applecontainer/... -run TestRunContainer_NamedVolume
  • go test ./runtime/applecontainer/... -run "TestRunContainer_BindMount|TestLifecycle_EndToEnd|TestInspectContainer" (no regression)
  • End-to-end: dap compose project comes up on apple backend with named volume mounted correctly

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved container mount resolution by processing mounts asynchronously for more reliable mounting.
    • Corrected named-volume handling so volumes are properly identified and mounted using inspected volume metadata.
  • Tests

    • Added an end-to-end test validating named volume mount behavior, including mount type and reported source verification.

Review Change Stack

The bridge's toFilesystem mapped MountType=volume to a virtiofs bind
against the spec's source string. Apple's apiserver doesn't recognize
that shape for named volumes and normalizes the source via
URL(fileURLWithPath:), which resolves it relative to the launching
process's CWD — yielding paths like /private/tmp/runner/<projname>_<vol>
that don't exist, and surface as `errno 2` / "vminitd.log doesn't exist"
when the VM tries to bootstrap.

Fix: resolve the volume name through ClientVolume.inspect to fetch the
backing image path and filesystem format, then construct a real
Filesystem.volume(...) — matching the shape apple/container's own CLI
emits for `container run -v <name>:/dest`. toFilesystem becomes async
since ClientVolume.inspect is async; the call site loops instead of
map.

Surfaced while bringing up a compose-source devcontainer
(crunchloop/dap) on the applecontainer backend through
compose.Orchestrator — the app service's claude-config named volume
hit this path.

Add TestRunContainer_NamedVolume as a regression guard: creates a
volume via the CLI, runs a container with MountVolume against it,
asserts the inspect path round-trips a MountVolume mount with a
non-empty source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a28e6780-f047-4741-98f0-0702b76b2b4e

📥 Commits

Reviewing files that changed from the base of the PR and between 8338add and 15d2c29.

📒 Files selected for processing (1)
  • runtime/applecontainer/lifecycle_darwin_arm64_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • runtime/applecontainer/lifecycle_darwin_arm64_test.go

📝 Walkthrough

Walkthrough

This PR converts mount resolution in runContainer to async, updates toFilesystem to be async throws, and changes named-volume handling to inspect the named volume (ClientVolume.inspect) and construct a Filesystem.volume; it adds an end-to-end test verifying named-volume mounts.

Changes

Async Named-Volume Resolution

Layer / File(s) Summary
Async mount resolution in runContainer and toFilesystem signature
applecontainer-bridge/Sources/ACBridge/lifecycle.swift
runContainer builds cfg.mounts by asynchronously iterating through spec.mounts and awaiting an async throws toFilesystem helper instead of using a synchronous map.
Named-volume inspection logic
applecontainer-bridge/Sources/ACBridge/lifecycle.swift
In the volume mount branch, named volumes are resolved by calling ClientVolume.inspect and constructing a Filesystem.volume from inspected name, format, and source, replacing the previous virtiofs bind-from-spec behavior.
E2E test validation
runtime/applecontainer/lifecycle_darwin_arm64_test.go
Adds TestRunContainer_NamedVolume (plus imports) which creates a Docker named volume, runs an Alpine container mounting it at /mnt/data, inspects container mounts to verify the mount Target, Type == MountVolume, and that Source is non-empty and not under the test runner CWD, then cleans up.

Sequence Diagram

sequenceDiagram
  participant runContainer
  participant toFilesystem
  participant ClientVolume
  participant Filesystem
  runContainer->>toFilesystem: await toFilesystem(mountSpec)
  toFilesystem->>ClientVolume: inspect(volumeName) [for volume mounts]
  ClientVolume-->>toFilesystem: volume metadata (name, format, source)
  toFilesystem->>Filesystem: construct Filesystem.volume from metadata
  toFilesystem-->>runContainer: return Filesystem
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • crunchloop/devcontainer#62: Related lifecycle mount-conversion changes in the Apple container bridge that introduced earlier mount handling patterns.

Poem

A rabbit sniffs the mounted field,
Inspects the volume, secrets yield.
Async hops from call to call,
Named mounts answer — one and all. 🐇📦

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing how named volume mounts are handled in applecontainer by properly wiring the volume inspect lookup instead of treating them as virtiofs binds.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/applecontainer-named-volumes

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@runtime/applecontainer/lifecycle_darwin_arm64_test.go`:
- Around line 224-230: The test currently only asserts m.Source is non-empty but
omits the "not launcher CWD" check described in the comment; fetch the test's
current working directory (e.g., via os.Getwd()) and add an explicit assertion
that m.Source is not equal to that launcher CWD (use the same t.Errorf style as
the existing check), referencing m.Source and the obtained cwd value so the test
fails if the source is exactly the launcher's working directory.
🪄 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

Run ID: 55ca24a4-6a60-496b-9798-2f63283f3f2d

📥 Commits

Reviewing files that changed from the base of the PR and between 160359a and 8338add.

📒 Files selected for processing (2)
  • applecontainer-bridge/Sources/ACBridge/lifecycle.swift
  • runtime/applecontainer/lifecycle_darwin_arm64_test.go

Comment thread runtime/applecontainer/lifecycle_darwin_arm64_test.go
The original bug produced a non-empty source — the failing path was
"/private/tmp/<launcher cwd>/<volname>" — so the existing "Source != ''"
check would have passed it. Add an explicit "source isn't CWD-prefixed"
guard so this test catches the exact shape of the regression.

Per CodeRabbit review on PR #67.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bilby91 bilby91 merged commit 4dd3c64 into main May 16, 2026
18 checks passed
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