@@ -142,7 +142,16 @@ jobs:
142142 sudo apptainer build /tmp/openms.sif docker-archive:///tmp/image.tar
143143 sudo chmod a+r /tmp/openms.sif
144144
145- - name : Start apptainer instance (read-only root, host UID)
145+ - name : Prepare host bind dirs (mountpoint contract)
146+ run : |
147+ # Host paths we'll bind into the SIF. Asserting writability through
148+ # singularity's bind machinery requires that the destination paths
149+ # exist as real directories in the squashfs (otherwise singularity
150+ # silently degrades the bind to read-only via underlay).
151+ mkdir -p /tmp/host-workspaces /tmp/host-mounted-data
152+ echo "from-host-pretest" > /tmp/host-mounted-data/sentinel.txt
153+
154+ - name : Start apptainer instance (read-only root, host UID, with binds)
146155 run : |
147156 # Default apptainer semantics: read-only root, no --writable-tmpfs.
148157 # This matches how users on HPC clusters run the SIF.
@@ -151,7 +160,10 @@ jobs:
151160 # Docker ENTRYPOINT but leaves %startscript as the default no-op
152161 # `exec "$@"`. `instance start` would launch an empty instance and
153162 # streamlit would never bind 8501.
154- apptainer instance run /tmp/openms.sif openms-test
163+ apptainer instance run \
164+ --bind /tmp/host-workspaces:/workspaces-streamlit-template:rw \
165+ --bind /tmp/host-mounted-data:/mounted-data:ro \
166+ /tmp/openms.sif openms-test
155167 apptainer instance list
156168 # Record where this run's logs will land so subsequent steps can tail
157169 # them deterministically (path depends on hostname/user).
@@ -195,6 +207,29 @@ jobs:
195207 run : |
196208 apptainer exec instance://openms-test redis-cli ping | grep -i pong
197209
210+ - name : Verify bind mount is writable (workspaces) and readable (data)
211+ run : |
212+ # The whole point of pre-creating /workspaces-streamlit-template
213+ # and /mounted-data in the image: singularity now has a real
214+ # attach point and `:rw` actually sticks. Without the mkdir,
215+ # `apptainer exec ... touch` here would fail with EROFS.
216+ apptainer exec instance://openms-test sh -c \
217+ 'echo from-container > /workspaces-streamlit-template/probe.txt'
218+ test -f /tmp/host-workspaces/probe.txt
219+ grep -q from-container /tmp/host-workspaces/probe.txt
220+ # Read-only data mount should also be visible inside the container.
221+ apptainer exec instance://openms-test grep -q from-host-pretest /mounted-data/sentinel.txt
222+ # The mounted-drive browser uses os.path.ismount() to gate
223+ # rendering (existence is no longer enough now that the image
224+ # pre-creates the dir). Assert the kernel reports both paths as
225+ # real mount points so the detection function returns truthy.
226+ apptainer exec instance://openms-test python3 -c "
227+ import os, sys
228+ for p in ('/mounted-data', '/workspaces-streamlit-template'):
229+ assert os.path.ismount(p), f'{p} not reported as mount point'
230+ print(f'ismount({p}) = True')
231+ "
232+
198233 - name : Dump entrypoint logs on failure
199234 if : failure()
200235 run : |
0 commit comments