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 <hermes@nesquena.com>
This commit is contained in:
nesquena-hermes
2026-04-20 21:03:41 -07:00
committed by GitHub
parent 49ff8b3185
commit 3f484aec33
3 changed files with 7 additions and 4 deletions

View File

@@ -8,7 +8,7 @@
## [v0.50.124] — 2026-04-21 ## [v0.50.124] — 2026-04-21
### Fixed ### 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 ## [v0.50.123] — 2026-04-21

View File

@@ -76,7 +76,7 @@ RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/b
USER hermeswebuitoo USER hermeswebuitoo
COPY . /apptoo COPY --chown=hermeswebuitoo:hermeswebuitoo . /apptoo
# Bake the git version tag into the image so the settings badge works even # Bake the git version tag into the image so the settings badge works even
# when .git is not present (it is excluded by .dockerignore). # when .git is not present (it is excluded by .dockerignore).

View File

@@ -49,10 +49,13 @@ class TestDockerfileUvPreinstall:
def test_dockerfile_uv_installed_before_copy(self): def test_dockerfile_uv_installed_before_copy(self):
"""uv installation must happen before COPY . /apptoo so it's in the image.""" """uv installation must happen before COPY . /apptoo so it's in the image."""
import re
uv_pos = DOCKERFILE.find("uv/install.sh") 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 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" assert uv_pos < copy_pos, "uv must be installed before COPY . /apptoo"
def test_dockerfile_uv_installed_as_root_or_before_user_switch(self): def test_dockerfile_uv_installed_as_root_or_before_user_switch(self):