fix(dab): run main compose service as root (0:0)#8
Merged
Conversation
Harbor's codex runtime pre-creates root-owned /logs/agent and $CODEX_HOME during setup, then runs the agent as the image's default USER. dab-agent:latest ships USER exedev (non-root), so the agent cannot write those dirs and codex aborts with "Permission denied (os error 13)". ade-bench's images run as root and never hit this. Pin the generated main service to user "0:0" to match the root images ade-bench runs successfully. Add a unit test asserting the main service is emitted with user "0:0". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes DAB task failures under Harbor’s codex runtime by ensuring the generated main docker-compose service runs as root (user: "0:0"), allowing it to write to root-owned directories that the runtime pre-creates.
Changes:
- Set
services.main.userto"0:0"in the generated compose YAML. - Add a unit test asserting the emitted
mainservice runs as root.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/razorback-plugin-dab/src/razorback_plugin_dab/generate/compose.py | Pins the main service to run as root (user: "0:0") to avoid permission errors in codex runtime. |
| packages/razorback-plugin-dab/tests/unit/test_compose_postgres.py | Adds coverage to ensure main.user is emitted as "0:0". |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+68
to
+72
| # /logs/agent and $CODEX_HOME, then harbor runs the agent as the image's | ||
| # default USER. dab-agent:latest is USER exedev (non-root), so the agent | ||
| # cannot write those dirs -> codex aborts with "Permission denied | ||
| # (os error 13)". Pin the main service to root so it can write them, | ||
| # matching the root images ade-bench runs successfully. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
DAB tasks fail under Harbor's codex runtime with:
The codex runtime's setup runs as root and pre-creates root-owned
/logs/agentand$CODEX_HOME, then Harbor runs the agent as theimage's default
USER.dab-agent:latestshipsUSER exedev(non-root), so the agent cannot write those root-owned dirs and codex
aborts before doing any work. ade-bench's images run as root, so they
never hit this — which is why the failure is DAB-specific.
Fix
Pin the generated
maincompose service touser: "0:0"so the agentruns as root and can write the pre-created dirs, matching the root
images ade-bench runs successfully.
Design note — why hardcoded, not spec-driven
Needing root is a property of the codex runtime contract (the
runtime pre-creates root-owned dirs for every DAB task), not a
per-task or per-dataset variable. So this is hardcoded at the compose
layer alongside the other fixed defaults (
POSTGRES_USER,DEFAULT_AGENT_IMAGE) rather than threaded as config with no consumer.If a future non-codex runtime needs a non-root agent, the clean seam is
a
run_as_user: str | None = "0:0"param throughprepare_dataset_tasks → generate_compose(omit the key whenNone) —out of scope for this bugfix.
Test
Adds
test_main_service_runs_as_rootasserting the emittedmainservice carries
user: "0:0".🤖 Generated with Claude Code