Files
hermes-agent/tests/test_dockerfile_tini_compat_shim.py
Bartok a60bff282e fix(docker): add /usr/bin/tini compatibility shim for legacy wrappers (#34192) (#34382)
#34192 reports Hostinger's 'Hermes WebUI' catalog crashes on startup
with:

  /usr/bin/tini: No such file or directory

The image moved from tini to s6-overlay as PID 1 (/init) earlier in
2026. Orchestration templates that still pin /usr/bin/tini as the
entrypoint \u2014 like the Hostinger Hermes WebUI catalog \u2014 have no
binary to exec and the container crashes immediately.

Hermes has no control over the Hostinger catalog template, but we can
make the image backward-compatible by symlinking /usr/bin/tini -> /init
during the s6-overlay install step. External wrappers that exec
/usr/bin/tini will land on the same s6-overlay reaper they would have
landed on if they'd used the canonical /init entrypoint.

The image's own ENTRYPOINT continues to be /init verbatim \u2014 the shim
is purely for legacy external wrappers, not for the image's own
runtime path. Once affected catalogs are updated, the symlink can be
removed.

Other issues #34192 raises that are NOT addressed by this PR:

  * Problem #2 (UID 1024 vs 10000 mismatch): already fixed by #33148
    (S6_KEEP_ENV=1) and #32412 (with-contenv shebangs). The Hostinger
    template likely needs to update its env-var propagation.

  * Problem #3 (incompatible session formats): RFC for pluggable
    SessionDB is tracked in #23717.

  * Problem #4 (Telegram polling conflict): an operations problem on
    Hostinger's side, not in this codebase.

This PR is scoped to the one issue that can be fixed inside
Dockerfile: the missing /usr/bin/tini binary.

Tests (3 in test_dockerfile_tini_compat_shim.py):

  - test_tini_compat_symlink_present
    Guard: the symlink line must exist in Dockerfile.
  - test_tini_compat_comment_explains_why
    The #34192 anchor comment must be present so future readers know
    why the shim is there (avoid accidental removal).
  - test_entrypoint_still_init_not_tini
    Sanity check: ENTRYPOINT remains /init (s6-overlay). The shim is
    only for external wrappers.

Refs: #34192
Partial fix: addresses the immediate tini-binary crash. Catalog-side
fixes still needed by Hostinger for the UID and session-format
problems documented in the issue.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 13:32:55 +10:00

50 lines
1.8 KiB
Python

"""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."
)