Skip to content

feat: distribute HALOS_DOMAIN via EnvironmentFile; stop hardcoding .local in generated prestarts#208

Merged
mairas merged 5 commits into
mainfrom
feat/domain-envfile-distribution
Jun 15, 2026
Merged

feat: distribute HALOS_DOMAIN via EnvironmentFile; stop hardcoding .local in generated prestarts#208
mairas merged 5 commits into
mainfrom
feat/domain-envfile-distribution

Conversation

@mairas

@mairas mairas commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What

Units 2 & 3 of #206 — centralize HALOS_DOMAIN so it's resolved once and distributed, instead of being independently resolved (and .local-hardcoded) in every generated prestart.

The producer (halos-resolve-domain.service, shipped in halos-core-containers 0.5.0 via #195) resolves the canonical hostname from hostnames.conf once and publishes /run/halos/domain.env. This change makes the generator consume it.

How

For routed/web_ui apps (predicate _has_routing = routing: present or web_ui.enabled):

  • service.j2 — add After=/Wants=halos-resolve-domain.service and EnvironmentFile=-/run/halos/domain.env, loaded last so it overrides any stale HALOS_DOMAIN a legacy runtime.env still carries. This is the only layer that reaches custom-prestart apps, since the unit is always generated even when prestart.sh is supplied verbatim.
  • control — inject Depends: halos-core-containers (>= 0.5.0).
  • prestart.py — stop resolving HALOS_DOMAIN and stop hardcoding ${HOSTNAME}.local; inherit HALOS_DOMAIN from the unit environment and build HOMARR_URL from it. No consumer writes HALOS_DOMAIN back to a file that's later re-read, so the runtime.env-as-EnvironmentFile feedback loop is structurally gone (R3). The vestigial top-level traefik metadata read is dropped.

A single _has_routing(metadata) predicate drives the unit wiring (service.j2's has_routing) and the control dependency (_compute_producer_depends), so the two can't drift — same discipline as registry.emits_path_only_url.

Requirements covered: R1, R2, R3, R4. (R5 rollout / R6 marine cleanup are Units 4–5 in other repos.)

Depends vs Breaks

Depends (not Breaks) is deliberate, and consistent with the Breaks-over-Depends policy: Breaks is for optional peers. halos-core-containers is part of the minimum install on every device that ships routed/web_ui apps (Traefik/Authelia/Homarr are the web-management layer they route through), so the peer is always present — line 53 of that policy endorses Depends for an always-present peer. The producer-absent failure mode (empty HALOS_DOMAIN → broken OIDC) is not graceful, so the constraint is kept rather than dropped under the skip-pins policy. Rationale recorded in AGENTS.md.

Rollout ordering (gates Units 4–5)

>= 0.5.0 is correct, but halos-core-containers 0.5.0 is not yet a published stable release (latest stable is v0.4.4+1). Downstream container repos that regenerate against this must not be promoted to stable until core 0.5.0 stable lands in apt, or their rebuilt .debs become uninstallable. Tracked under #206's risk table and Unit 5.

Testing

uv run pytest -m "not install" → 586 passed / 1 skipped. Lint, format clean; ty clean except 2 pre-existing diagnostics in untouched routing.py. New tests cover: web_ui app wiring, OIDC app (both Authelia + producer ordering), the routing-present/no-web_ui branch, domain.env as the last EnvironmentFile, and the non-routed app staying independent of the producer.

Refs #206

🤖 Generated with Claude Code

mairas and others added 5 commits June 15, 2026 00:43
…ucer ordering

Routed and web_ui apps' generated units now load /run/halos/domain.env
(published once by halos-resolve-domain.service), order against and softly
want that producer, and depend on the core release that ships it
(halos-core-containers >= 0.5.0). The env file is loaded last so it wins over
any stale HALOS_DOMAIN a legacy runtime.env might still carry, which closes
the runtime.env-as-EnvironmentFile feedback loop.

This is the only layer that reaches custom-prestart apps, since the unit is
always generated even when prestart.sh is supplied verbatim.

The versioned Depends is kept despite the workspace skip-apt-depends-pins
policy: of the three protective layers only cohort-upgrade holds — an absent
producer leaves HALOS_DOMAIN empty (broken OIDC URLs), which is not graceful
degradation, and there is no runtime probe. 1-of-3 means the pin earns its
cost.

Refs #206 (Unit 2)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The generated prestart no longer resolves HALOS_DOMAIN or hardcodes
${HOSTNAME}.local; it inherits HALOS_DOMAIN from the unit environment and
builds HOMARR_URL from it. No consumer writes HALOS_DOMAIN back to a file
that is later re-read, so the feedback loop is structurally gone. The
vestigial top-level `traefik` metadata read is dropped with it.

Refs #206 (Unit 3)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ependency

Address review findings on the HALOS_DOMAIN distribution change:

- Extract `_has_routing(metadata)` as the single source of truth for
  routing-eligibility, used by both `build_context` (which drives the systemd
  ordering and EnvironmentFile in service.j2) and `_compute_producer_depends`
  (which drives the control dependency). Previously each recomputed the
  predicate inline; sharing it follows the `emits_path_only_url` discipline and
  removes the risk of unit wiring and package dependency drifting apart.
- Document HALOS_CORE_CONTAINERS_PRODUCER_MIN_VERSION and the producer wiring in
  AGENTS.md, matching the existing convention for generator-injected version
  constants. Records why Depends (not Breaks) is correct here: core is always
  present on routed/web_ui devices.
- Add tests for the OIDC app (both authelia + producer ordering), the
  routing-present/no-web_ui branch, and assert domain.env is the last
  EnvironmentFile.

Refs #206 (Unit 2)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mairas mairas merged commit d6cd499 into main Jun 15, 2026
4 checks passed
@mairas mairas deleted the feat/domain-envfile-distribution branch June 15, 2026 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant