feat: Composable prestart hook (Plan A: capability + docs)#212
Conversation
…hook Always generate the framework prestart.sh; a custom prestart.sh becomes a sourced app-prestart.sh hook installed beside docker-compose.yml, instead of the all-or-nothing replacement. Create runtime.env mode 600 before any write (survives appends), drop the unused HOSTNAME write from the container env, and gate the hook install on has_app_prestart.
…doc tmpfs secret note Address code-review findings: assert the hook is sourced after the last runtime.env append (not the declaration); guard the no-web_ui branch against a truncating write; cover HOMARR_URL+hook coexistence; pin the rules.j2 install dir to the prestart source dir; document that runtime.env is tmpfs-recreated so hook secrets must persist to the data dir.
Code review — composable prestart hookAutomated multi-persona review (correctness, testing, maintainability, project-standards, security, reliability, adversarial lenses) over the diff. Verdict: Ready to merge. The capability is correct and well-tested: the P1 — High (tracked, not a defect in this diff)
P2 — Moderate
P3 — Low (all fixed or advisory)
Security findings were all confirmations that the design is sound (atomic Applied fixes (
|
Motivation
generate_prestart_filecopied a customprestart.shverbatim and skippedgeneration, so any app needing one custom step had to re-implement all framework
boilerplate (runtime dir, env sourcing,
HOSTNAME/HOMARR_URL). Thatduplicated-boilerplate class is what shipped the
HALOS_DOMAINbug (#177). Thisis Plan A (#207): the capability + docs, shipped first and independently of
declarative OIDC (Plan B, #211) and the legacy cleanup (Plan C, #210).
Approach
prestart.shis now always the framework scaffolding andends by sourcing an optional
app-prestart.shhook. An app that ships aprestart.shhas it copied into the package asapp-prestart.sh, besidedocker-compose.yml(so hooks resolving their own dir viaBASH_SOURCEstill find the compose file).
runtime.envis framework-owned: created mode600(install -m 600 /dev/null)before any write, so the mode predates content and survives every append. The
hook contract is append-only to
$RUNTIME_ENV.HOSTNAMEis dropped from the container env (HOMARR_URLis built from${HALOS_DOMAIN}, nothostname -s, so it was unused).set -epropagates hook failures to unit start.$RUNTIME_ENVappend-only,$HALOS_DOMAIN,sourced env, hook dir,
set -esemantics, static seed →default-data/) inAGENTS.md / EXAMPLES.md.
Scope
Capability + docs only. No OIDC work (Plan B), no legacy
traefik/oidc_snippetremoval (Plan C), and no marine app migration (that lands as one coordinated PR
after Plan B also ships — the marine repo builds all apps under a single
CONTAINER_TOOLS_REF).Verification
tests/test_prestart.py/test_builder.py: plain and custom-logic apps bothget framework scaffolding + the hook-source line;
runtime.envis600;app-prestart.shis a sibling ofdocker-compose.yml; a compliant append-onlyhook coexists with framework
HOSTNAME/HOMARR_URLlines.Implements Plan A Units 1 & 4 of #207.