fix(publish-template-image): chmod a+rX + drop :ro so agent can read /configs
Hot-fix for #2275 Phase 2 — the boot smoke step in v1@3c8f8fe failed on every template publish with `PermissionError: [Errno 13] Permission denied: '/configs/config.yaml'` because `mktemp -d` creates the dir with mode 700 and `chmod -R go+r` adds 'r' to files but doesn't add 'x' to directories. Inside the image the entrypoint drops priv to uid 1000 (agent), which then cannot traverse /configs to even reach config.yaml — main.py exits before any executor code runs. Two changes: 1. `chmod -R a+rX` (capital X) adds 'x' to directories AND already- executable files, so the temp dir becomes traversable for agent while config.yaml stays a regular world-readable file. 2. Drop `:ro` on the mount so the entrypoint's `chown -R agent /configs` succeeds. The container is ephemeral; modifications to the host mktemp dir don't matter and the dir gets nuked right after the smoke run. Reproduced + diagnosed against claude-code publish run 25202651546 which failed within a few seconds on Path('/configs/config.yaml').exists() in molecule_runtime/config.py:298. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3c8f8fe48b
commit
a5212a349b
19
.github/workflows/publish-template-image.yml
vendored
19
.github/workflows/publish-template-image.yml
vendored
@ -287,11 +287,22 @@ jobs:
|
|||||||
|
|
||||||
# Mount the repo's own config.yaml at /configs so the runtime
|
# Mount the repo's own config.yaml at /configs so the runtime
|
||||||
# can reach create_executor() — that's where the lazy imports
|
# can reach create_executor() — that's where the lazy imports
|
||||||
# we want to test actually live. World-readable so the
|
# we want to test actually live. The image's entrypoint drops
|
||||||
# entrypoint's drop-priv to uid 1000 can read it.
|
# priv from root to agent (uid 1000) before exec'ing
|
||||||
|
# molecule-runtime, so /configs needs to be readable AND
|
||||||
|
# traversable from uid 1000.
|
||||||
|
#
|
||||||
|
# Use `a+rX` (capital X — only adds x where it's already
|
||||||
|
# executable, i.e. directories): mktemp -d creates the dir
|
||||||
|
# with mode 700, so a bare `go+r` would leave the dir
|
||||||
|
# un-traversable for agent and config.py would
|
||||||
|
# PermissionError on `Path('/configs/config.yaml').exists()`.
|
||||||
|
# Mount RW (not :ro) so the entrypoint's `chown -R agent
|
||||||
|
# /configs` succeeds — its silent chown failure on a :ro
|
||||||
|
# mount was the original symptom.
|
||||||
SMOKE_CONFIG_DIR=$(mktemp -d)
|
SMOKE_CONFIG_DIR=$(mktemp -d)
|
||||||
cp config.yaml "${SMOKE_CONFIG_DIR}/"
|
cp config.yaml "${SMOKE_CONFIG_DIR}/"
|
||||||
chmod -R go+r "${SMOKE_CONFIG_DIR}"
|
chmod -R a+rX "${SMOKE_CONFIG_DIR}"
|
||||||
|
|
||||||
# Stub credentials — adapters validate shape at create_executor
|
# Stub credentials — adapters validate shape at create_executor
|
||||||
# time but the smoke times out before any real call goes out.
|
# time but the smoke times out before any real call goes out.
|
||||||
@ -299,7 +310,7 @@ jobs:
|
|||||||
# specific key sees a non-empty value.
|
# specific key sees a non-empty value.
|
||||||
set +e
|
set +e
|
||||||
timeout 60 docker run --rm \
|
timeout 60 docker run --rm \
|
||||||
-v "${SMOKE_CONFIG_DIR}:/configs:ro" \
|
-v "${SMOKE_CONFIG_DIR}:/configs" \
|
||||||
-e WORKSPACE_ID=fake-smoke \
|
-e WORKSPACE_ID=fake-smoke \
|
||||||
-e MOLECULE_SMOKE_MODE=1 \
|
-e MOLECULE_SMOKE_MODE=1 \
|
||||||
-e MOLECULE_SMOKE_TIMEOUT_SECS=10 \
|
-e MOLECULE_SMOKE_TIMEOUT_SECS=10 \
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user