diff --git a/Dockerfile b/Dockerfile index f1e04a3b6..660257d7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -73,7 +73,17 @@ RUN set -eu; \ tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz; \ tar -C / -Jxpf /tmp/s6-overlay-arch.tar.xz; \ tar -C / -Jxpf /tmp/s6-overlay-symlinks-noarch.tar.xz; \ - rm /tmp/s6-overlay-*.tar.xz /tmp/s6-overlay.sha256 + rm /tmp/s6-overlay-*.tar.xz /tmp/s6-overlay.sha256; \ + # #34192: backward-compat shim for orchestration templates that still\ + # reference the legacy /usr/bin/tini entrypoint (e.g. Hostinger's\ + # 'Hermes WebUI' catalog). The image has moved to s6-overlay /init\ + # as PID 1 (see ENTRYPOINT below + the migration comment at the top\ + # of this file), but external wrappers pinned to /usr/bin/tini will\ + # crash with 'tini: No such file or directory' on startup. The shim\ + # symlinks /usr/bin/tini -> /init so legacy wrappers exec the right\ + # PID-1 reaper without behavior change for users on the current\ + # ENTRYPOINT. Safe to drop once the affected catalogs are updated.\ + ln -sf /init /usr/bin/tini # Non-root user for runtime; UID can be overridden via HERMES_UID at runtime RUN useradd -u 10000 -m -d /opt/data hermes diff --git a/tests/test_dockerfile_tini_compat_shim.py b/tests/test_dockerfile_tini_compat_shim.py new file mode 100644 index 000000000..e396c8625 --- /dev/null +++ b/tests/test_dockerfile_tini_compat_shim.py @@ -0,0 +1,49 @@ +"""Regression test for #34192 — Dockerfile must keep the tini compat shim +for orchestration templates that still reference /usr/bin/tini. + +This is a documentation-as-test guard: removing the shim is a real +choice, but it should be done deliberately (e.g. once Hostinger's +'Hermes WebUI' catalog updates to /init) and not by accident. +""" + +from __future__ import annotations + +from pathlib import Path + + +def _dockerfile_text() -> str: + return (Path(__file__).parent.parent / "Dockerfile").read_text(encoding="utf-8") + + +def test_tini_compat_symlink_present(): + """The /usr/bin/tini -> /init symlink line must exist for #34192.""" + df = _dockerfile_text() + assert "ln -sf /init /usr/bin/tini" in df, ( + "Dockerfile must keep the tini compat symlink (#34192). " + "Removing it breaks orchestration templates that still pin " + "/usr/bin/tini as the entrypoint (Hostinger 'Hermes WebUI' " + "catalog as of v0.14.x)." + ) + + +def test_tini_compat_comment_explains_why(): + """The symlink line is comment-anchored to #34192 so a future reader + knows why it exists. Removing the comment makes it look like dead + code worth deleting.""" + df = _dockerfile_text() + assert "#34192" in df, ( + "The Dockerfile tini compat shim must keep its #34192 anchor " + "comment so future maintainers know why the symlink is there." + ) + + +def test_entrypoint_still_init_not_tini(): + """Sanity check: the actual ENTRYPOINT is still /init (s6-overlay). + The shim is for legacy external wrappers, not for the image's own + runtime — that path must continue to use the canonical /init.""" + df = _dockerfile_text() + assert 'ENTRYPOINT [ "/init"' in df, ( + "Dockerfile ENTRYPOINT must remain /init (s6-overlay). The " + "tini shim is only for external wrappers that haven't been " + "updated yet." + )