compose: apply feature security metadata + entrypoint chaining to services#103
Conversation
…vices Dev Container Features declare security options (privileged, init, capAdd, securityOpt) and entrypoint scripts in their metadata. For image/Dockerfile devcontainers these become `docker run` flags; the reference devcontainers/cli also applies them to docker-compose services via its generated override compose file. Our compose path merged the metadata into ResolvedConfig but never carried it onto the service, so features like docker-in-docker silently failed on compose-source devcontainers: the daemon came up unprivileged and its docker-init.sh entrypoint never ran, so `docker` reported the daemon down. Security options: - Extend compose.Override with Privileged/Init/CapAdd/SecurityOpt; build it once from cfg in createFreshCompose and apply on both backends (ApplyRunOverride for native, WriteRunOverride YAML for shellout). - serviceToRunSpec now forwards Privileged/SecurityOpt to RunSpec (Init/CapAdd were already mapped). Entrypoint chaining: - Aggregate the metadata entrypoint chain into ResolvedConfig.Entrypoints (base-image label entries first, then features; idempotent). - RenderEntrypointWrapper builds the `/bin/sh -c '<each entrypoint>; exec "$@"'` wrapper that runs feature entrypoints before the original entrypoint+command. Native path emits a single `$`; shellout path doubles to `$$` because `docker compose` re-interpolates the written YAML. - Add ImageDetails.Entrypoint (+ docker InspectImage) so a non-null image ENTRYPOINT is preserved underneath the wrapper. Inspect contract: ContainerDetails gains Privileged/CapAdd/SecurityOpt (read from HostConfig in docker InspectContainer, reused by podman) so the new integration test can verify what landed on the real container. Applecontainer can't surface these (VM isolation) — left at zero values. Tested: unit coverage for the wrapper rendering, override apply/emit, and metadata aggregation; integration test brings up a compose devcontainer whose feature declares privileged/init/capAdd/securityOpt + an entrypoint and asserts all of them land on the real container — green on both native and shellout backends. Image-source (non-compose) entrypoint chaining is left as a follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe PR adds ordered entrypoint chaining and security metadata propagation across compose metadata merging, override generation/application, runtime inspection, and integration coverage for native and shellout compose backends. ChangesCompose security and entrypoint chaining
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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 `@up.go`:
- Around line 567-574: The InspectImage fallback in the entrypoint selection
logic is swallowing errors, so failed image inspection can silently leave
origEntrypoint unset while wrapper entrypoints are still applied. Update the
Entrypoints handling in the code around e.runtime.InspectImage to log the
inspect error when the service has no Entrypoint and finalImage inspection
fails, using the existing context from cfg.Entrypoints/src.Service so the
fallback behavior is observable and easier to diagnose.
🪄 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: 78f9500f-ab79-4ecf-b96c-e6776318a803
📒 Files selected for processing (14)
compose/apply_override.gocompose/apply_override_test.gocompose/orchestrator.gocompose/orchestrator_test.gocompose/override.gocompose/override_test.goconfig/merge_metadata.goconfig/merge_metadata_test.goconfig/resolved.goruntime/applecontainer/inspect_darwin_arm64.goruntime/docker/inspect.goruntime/runtime.gotest/integration/compose_feature_security_test.goup.go
When a feature declares an entrypoint and the compose service declares none, we inspect the final image to preserve its ENTRYPOINT under the wrapper. A failed inspect left origEntrypoint nil and silently dropped the image ENTRYPOINT from `exec "$@"`. Emit a WarnEvent so the fallback is observable. Addresses CodeRabbit review on #103. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Document everything merged since v0.3.0: Podman backend + checkpoint/restore (#98), compose feature security metadata + entrypoint chaining (#103), Podman compose health probing (#102), deps bump (#101), and the prebuild dev-environment / CI tooling (#88–#93). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem
Dev Container Features declare security options (
privileged,init,capAdd,securityOpt) andentrypointscripts in their metadata. For image/Dockerfile devcontainers these becomedocker runflags; the referencedevcontainers/clialso applies them to docker-compose services via its generated override compose file (generateFeaturesComposeOverrideContent).Our compose path merged the metadata into
ResolvedConfigbut never carried it onto the service. So a feature like docker-in-docker silently failed on compose-source devcontainers:docker-init.shentrypoint never ran,…so
dockerinside the container reported the daemon was down. This was hit in real use on the DAP devcontainer (prebuilt image carrying dind in itsdevcontainer.metadatalabel).Fix
Security options
compose.OverridewithPrivileged/Init/CapAdd/SecurityOpt; build it once fromcfgincreateFreshComposeand apply on both backends —ApplyRunOverride(native, in-memory project mutate) andWriteRunOverride(shellout YAML).serviceToRunSpecnow forwardsPrivileged/SecurityOpttoRunSpec(Init/CapAddwere already mapped).Entrypoint chaining
ResolvedConfig.Entrypoints(base-image label entries first, then features; idempotent).RenderEntrypointWrapperbuilds the/bin/sh -c '<each entrypoint>; exec "$@"'wrapper that runs feature entrypoints before the original entrypoint+command. Native path emits a single$; shellout path doubles to$$becausedocker composere-interpolates the written YAML.ImageDetails.Entrypoint(+ dockerInspectImage) so a non-null imageENTRYPOINTis preserved underneath the wrapper.Inspect contract
ContainerDetailsgainsPrivileged/CapAdd/SecurityOpt, read fromHostConfigin dockerInspectContainer(reused by the podman backend), so tests can verify what actually landed on the container. Applecontainer can't surface these (VM isolation) — left at zero values.Testing
$), override apply + YAML emit, and metadata aggregation/idempotency.TestComposeSource_FeatureSecurityOptionsApplied): brings up a compose devcontainer whose feature declaresprivileged/init/capAdd/securityOptand anentrypoint, then asserts all of them land on the real container via inspect + that the entrypoint marker ran. Green on bothnativeandshelloutbackends.Scope / follow-up
Image-source (non-compose) entrypoint chaining is intentionally not included —
newRunSpecdoesn't consumecfg.Entrypointsyet because the interaction withOverrideCommand/keep-alive is delicate. The reported case (compose) is fully covered. Tracked as a follow-up.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests