Skip to content

Fix frontend directory permissions in omnibus image (COPY --chmod=644 strips directory search bit) - #1035

Open
schainks wants to merge 1 commit into
AnalogJ:masterfrom
schainks:fix/web-dir-permissions
Open

Fix frontend directory permissions in omnibus image (COPY --chmod=644 strips directory search bit)#1035
schainks wants to merge 1 commit into
AnalogJ:masterfrom
schainks:fix/web-dir-permissions

Conversation

@schainks

@schainks schainks commented Jul 21, 2026

Copy link
Copy Markdown

Closes #1037 (accepted from discussion #1036; maintainer go-ahead for an AI-authored PR here).

AI disclosure (per AI_POLICY.md): diagnosis, this fix, and the PR text were produced with Claude Code. I (schainks) reviewed and edited the output, and verified the root cause and the fix's effect on my own hardware (Ubuntu 24.04, v0.9.2-omnibus, hardened compose with cap_drop: ALL). Nothing here is hypothetical-untested code.

Problem

docker/Dockerfile copies the frontend with --chmod=644. BuildKit applies --chmod to directories as well as files, so /opt/scrutiny/web ships without execute/search bits:

$ docker run --rm --entrypoint sh ghcr.io/analogj/scrutiny:v0.9.2-omnibus -c 'ls -lan /opt/scrutiny/web | head -3'
drw-r--r-- 3 0 0 4096 ... .

Default-root deployments mask this via CAP_DAC_OVERRIDE. Hardened ones (cap_drop: ALL) get EACCES on everything under that directory: /web/ renders a raw directory listing (FileServer can't open index.html), static routes return 403, and HEAD /api/health 403s — which also hangs the omnibus collector-once wait loop ("scrutiny api not ready" forever), so the boot-time collector run never happens.

This is a regression of #502: the fix in #520 (chmod -R a+rX /opt/scrutiny in the old Dockerfile.web) was lost when consolidating into the omnibus Dockerfile.

Fix

One line: --chmod=644--chmod=755 on the frontend COPY, restoring directory traversal. Execute bits on the static asset files are harmless. If you'd rather keep files at 644 exactly, the alternative is dropping --chmod/--link and adding RUN chmod -R u=rwX,go=rX /opt/scrutiny/web at the cost of the --link layer optimization — happy to switch the PR if preferred.

Verification

On the affected deployment, restoring directory readability (validated with CAP_DAC_READ_SEARCH, which has the same read-side effect as this fix) resolves all three symptoms: /web/ serves the app, routes return 200, and collector-once completes on boot.

COPY --chmod=644 applies mode 644 to directories as well as files
(BuildKit --chmod does not distinguish), so /opt/scrutiny/web ships
without execute/search bits. Containers running with default root
capabilities never notice because CAP_DAC_OVERRIDE bypasses the check,
but hardened deployments (cap_drop: ALL) get EACCES on every file:
/web/ renders a raw directory listing instead of index.html, static
routes return 403, and HEAD /api/health 403s, which also hangs the
omnibus collector-once wait loop.

Use --chmod=755 so directories are traversable; file execute bits on
static assets are harmless.
@schainks

Copy link
Copy Markdown
Author

Closing this — I jumped straight to a PR without going through the Issue Triage process in CONTRIBUTING.md, and it wasn't tied to an accepted issue. Re-filing properly as a discussion first (this turns out to be a regression of #502 / #520). Apologies for the drive-by.

@schainks schainks closed this Jul 22, 2026
@schainks schainks reopened this Jul 22, 2026
@schainks schainks changed the title Fix frontend directory permissions in omnibus image (COPY --chmod=644 breaks hardened containers) Fix frontend directory permissions in omnibus image (COPY --chmod=644 strips directory search bit) Jul 22, 2026
@schainks
schainks marked this pull request as ready for review July 22, 2026 20:35
Comment thread docker/Dockerfile

COPY --link --from=backendbuild --chmod=755 /go/src/github.com/analogj/scrutiny/scrutiny /opt/scrutiny/bin/
COPY --link --from=backendbuild --chmod=755 /go/src/github.com/analogj/scrutiny/scrutiny-collector-metrics /opt/scrutiny/bin/
COPY --link --from=frontendbuild --chmod=644 /go/src/github.com/analogj/scrutiny/dist /opt/scrutiny/web

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont need +x on files. just dirs. thats why there was a separate chmod in the web container

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Running hardend container (cap_drop: ALL, i.e. without CAP_DAC_OVERRIDE) results in raw directory listing at /web/

2 participants