From 3f484aec3317d576dd3700adcf8d87b7a5813ead Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Mon, 20 Apr 2026 21:03:41 -0700 Subject: [PATCH] fix: add --chown to Dockerfile COPY so RUN can write api/_version.py (#793) The v0.50.124 Docker build failed with: cannot create /apptoo/api/_version.py: Permission denied Root cause: 'USER hermeswebuitoo' is set before 'COPY . /apptoo', but COPY without --chown creates files owned by root. The subsequent RUN step (which writes api/_version.py) runs as hermeswebuitoo and has no write permission to the root-owned api/ directory. Fix: COPY --chown=hermeswebuitoo:hermeswebuitoo so the unprivileged user owns the app files and can write _version.py at build time. Regression from #790. Co-authored-by: nesquena-hermes --- CHANGELOG.md | 2 +- Dockerfile | 2 +- tests/test_issue357.py | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9165b0d..0918caa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ ## [v0.50.124] — 2026-04-21 ### Fixed -- **Settings version badge now shows the real running version** — the badge in the Settings → System panel was hardcoded to `v0.50.87` (36 releases behind) and the HTTP `Server:` header said `HermesWebUI/0.50.38` (85 behind). Both are now resolved dynamically at server startup from `git describe --tags --always --dirty`. Docker images (where `.git` is excluded) receive the correct tag via a build-time `ARG HERMES_VERSION` written to `api/_version.py`. No manual "update the badge" step is needed going forward — tagging is sufficient. Version file parsing uses regex instead of `exec()` for supply-chain safety. (#790, #792) +- **Settings version badge now shows the real running version** — the badge in the Settings → System panel was hardcoded to `v0.50.87` (36 releases behind) and the HTTP `Server:` header said `HermesWebUI/0.50.38` (85 behind). Both are now resolved dynamically at server startup from `git describe --tags --always --dirty`. Docker images (where `.git` is excluded) receive the correct tag via a build-time `ARG HERMES_VERSION` written to `api/_version.py`. `COPY` now uses `--chown=hermeswebuitoo:hermeswebuitoo` so the write succeeds under the unprivileged container user. No manual "update the badge" step is needed going forward — tagging is sufficient. Version file parsing uses regex instead of `exec()` for supply-chain safety. (#790, #793) ## [v0.50.123] — 2026-04-21 diff --git a/Dockerfile b/Dockerfile index 06fb2ec..974e32e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -76,7 +76,7 @@ RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/b USER hermeswebuitoo -COPY . /apptoo +COPY --chown=hermeswebuitoo:hermeswebuitoo . /apptoo # Bake the git version tag into the image so the settings badge works even # when .git is not present (it is excluded by .dockerignore). diff --git a/tests/test_issue357.py b/tests/test_issue357.py index 450e77f..49ce59c 100644 --- a/tests/test_issue357.py +++ b/tests/test_issue357.py @@ -49,10 +49,13 @@ class TestDockerfileUvPreinstall: def test_dockerfile_uv_installed_before_copy(self): """uv installation must happen before COPY . /apptoo so it's in the image.""" + import re uv_pos = DOCKERFILE.find("uv/install.sh") - copy_pos = DOCKERFILE.find("COPY . /apptoo") + # Match COPY regardless of flags (e.g. --chown=...) — only the destination matters. + m = re.search(r"^COPY\b.*\s/apptoo\b", DOCKERFILE, re.MULTILINE) assert uv_pos != -1, "uv install not found in Dockerfile" - assert copy_pos != -1, "COPY . /apptoo not found in Dockerfile" + assert m is not None, "COPY ... /apptoo not found in Dockerfile" + copy_pos = m.start() assert uv_pos < copy_pos, "uv must be installed before COPY . /apptoo" def test_dockerfile_uv_installed_as_root_or_before_user_switch(self):