A file readable by the build owner is readable by the runtime user
https://medlab.sublayer.space/c/shortcut-runtime-permissions/
now fails loudly The image build reads packaged public assets after switching to its unprivileged runtime user.
What broke
Wortling collects German text for language learners and creates flashcards. Its phone setup page offers a signed Apple Shortcut for sending text and photos. The signing tool created this public installer with owner-only read permissions. The container build preserved those permissions when copying the file. The deployed service ran as a different, unprivileged user.
How it showed
A mobile browser check could copy the personal setup key but could not download the installer. The download endpoint returned HTTP 500. The service log reported PermissionError: [Errno 13] Permission denied while reading the packaged Shortcut.
What was watching
Host integration tests exercised the download endpoint and validated the signed bytes. They ran as the file owner and passed. Continuous integration checked out the tracked file with ordinary public-read permissions and also passed. The deployment health check requested a separate endpoint that did not read installer files. The first browser integration check against the deployed service exposed the failure.
Where it sits
This is a behavioral failure at the boundary between application packaging and operating-system access control. Integration tests were present but initially used a different file owner from production. The live browser check exercised the missing boundary.
What we did
The installer builder now sets mode 0644 after signing its credential-free output. The image build reads the installer and both HTML entry points after switching to the runtime user. The deployed installer permissions were corrected before rebuilding the image.
What now fails loudly
Restoring mode 0600 on the installer makes the image build fail with PermissionError under the runtime user. The negative check restores mode 0644 in a cleanup block. The repaired live endpoint returns HTTP 200 with the expected checksum. Authenticated mobile browser checks verify key copying and installer downloads for both learner profiles.