Skip to content

Commit 9529baa

Browse files
cailmdaleyclaude
andauthored
docker: smoke-test the example pipeline in read-only mode (#731)
`shapepipe_run -c /app/example/config.ini` succeeds in docker because the container filesystem is writable, but fails under apptainer/SIF because OUTPUT_DIR=./example/output resolves under WORKDIR=/app which is read-only: ERROR: [Errno 30] Read-only file system: './example/output/shapepipe_runs.txt' The CI smoke test was passing while the apptainer path silently broke — same class of gap dc13582 closed for `uv run pytest`, but for the pipeline entry point. Fix: a small wrapper `scripts/sh/shapepipe_run_example.sh` that mktemp's a workdir, copies /app/example into it, cd's, and execs shapepipe_run. The existing Dockerfile auto-symlink rule makes it available as `shapepipe_run_example` on $PATH. The CI step switches to the wrapper and runs it under `docker run --read-only --tmpfs /tmp:rw`, which emulates SIF semantics. Any future regression that relies on a writable cwd will fail here instead of silently breaking apptainer users. Drive-by: tighten `.gitignore`'s example-output patterns from `*shapepipe_run_*` (catches anything with that substring, including this new wrapper) to `example/output/shapepipe_run_*`. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent fa8b2c8 commit 9529baa

3 files changed

Lines changed: 24 additions & 5 deletions

File tree

.github/workflows/deploy-image.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,13 @@ jobs:
6363
docker run --rm "$IMAGE" weightwatcher --version
6464
docker run --rm "$IMAGE" psfex --version
6565
66-
- name: Test runtime — shapepipe entry point
66+
- name: Test runtime — shapepipe entry point (read-only fs)
6767
run: |
6868
IMAGE=$(echo "${{ steps.meta-runtime.outputs.tags }}" | head -n1)
69-
docker run --rm "$IMAGE" shapepipe_run -c /app/example/config.ini
69+
# --read-only + tmpfs /tmp emulates apptainer/SIF semantics: only
70+
# /tmp is writable. shapepipe_run_example wraps shapepipe_run so
71+
# the example tree gets copied into a mktemp workdir before running.
72+
docker run --rm --read-only --tmpfs /tmp:rw "$IMAGE" shapepipe_run_example
7073
7174
# Build dev (reuses cached `base` layer)
7275
- name: Build dev (load)

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ dmypy.json
130130
# Pyre type checker
131131
.pyre/
132132

133-
# Ignore example output
134-
*shapepipe_run_*
135-
*shapepipe_runs*
133+
# Ignore example output (generated under example/output/ by shapepipe_run)
134+
example/output/shapepipe_run_*
135+
example/output/shapepipe_runs*
136136
code
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
# Run the bundled example pipeline against a writable copy of /app/example.
3+
#
4+
# Works under both docker (writable /app) and apptainer/SIF (read-only /app):
5+
# the example tree is copied into a fresh tmp workdir so the config's
6+
# relative paths (INPUT_DIR=./example/data/..., OUTPUT_DIR=./example/output)
7+
# resolve to writable locations.
8+
#
9+
# Extra args are forwarded to shapepipe_run, e.g.:
10+
# shapepipe_run_example -v
11+
set -euo pipefail
12+
13+
WORK="$(mktemp -d -t shapepipe-example-XXXXXX)"
14+
cp -r /app/example "$WORK/"
15+
cd "$WORK"
16+
exec shapepipe_run -c example/config.ini "$@"

0 commit comments

Comments
 (0)