Files
kevinveenbirkenbachandClaude Opus 5.5 ae8a15b4e9 fix(install): give arm64 Ubuntu images a ports mirror list
Every arm64 Ubuntu CI image build failed twice on 2026-11-11 (14:11 to
14:34 and 15:58 to 16:18 UTC) with Could not resolve 'ports.ubuntu.com'
(PR #1477, job 130634835861). apt-mirrors.sh rewrote only the
archive.ubuntu.com and security.ubuntu.com sources to the mirror list;
arm64 images point at ports.ubuntu.com/ubuntu-ports, which the archive
mirrors do not carry, so ports.ubuntu.com stayed their single source.

INFINITO_APT_UBUNTU_PORTS_MIRRORS now lists ports.ubuntu.com, then
ftp.tu-chemnitz.de and mirrors.dotsrc.org (both official Launchpad
mirrors carrying ubuntu-ports with resolute and resolute-security, in
sync with ports.ubuntu.com). apt-mirrors.sh points the ports sources
at that list the same way the archive sources use theirs, the image
build passes the key through, and the external mirror test checks both
lists for speed, freshness and officiality.

🎯 Fix: 92 %
💥 Break: 3 %
💸 Cost: –
⏱️ Time: –
🛡️ Security: 75 %
🏆 Score: 67
🚦 Gate: ⚠️ security 75 % < 100: ask the operator before the commit

Security 75 % comes from Trivy DS-0002 (image user should not be root)
on the root Dockerfile, present on main before this change, which
touches no USER line; the finding carries no line, so security.py
cannot accept it. Committed on the operator's word with that cause
named.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 18:05:22 +00:00
..
…

utils/env 📐

This directory hosts the Python implementation behind make dotenv. For the general rules that govern READMEs in code directories see documentation.md. For the per-variable defaults that this code consumes see default.env.

Purpose 🎯

The package converts the committed default.env plus a small runtime context into the gitignored .env at the repo root. Every module here belongs to one of four roles: parse, resolve, orchestrate, write.

Structure 🗂️

File Role
parser.py Read default.env into (values, comments) tuples.
runtime.py Resolve host-context lookups (disk, RAM, hostname, GHA/Act flags, /proc/version, helper-script invocation).
builder.py Thin orchestrator that defines EnvBuilder, BuildContext, and build_env(). Walks the handler registry.
writer.py Serialise an EnvBuilder into a docker-compose-compatible .env on disk.
handlers/ One module per dynamically-computed variable. See handlers README.

The CLI entry point lives at __main__.py under cli/meta/env/. Shell consumers source load.sh under scripts/meta/env/.

File Naming 🏷️

  • Module names MUST stay lowercase snake_case.
  • Pure passthrough or simple parser/writer helpers MUST live directly under utils/env/.
  • Per-variable computation MUST live under handlers/ (see handlers README for the naming convention used there).
  • Test files live in tests/unit/python/utils/env/ and mirror the module name with a test_ prefix.

Machine Facts vs Run Facts 🧭

The writer a handler picks decides how long a value lives. Both kinds are registered in default.env and both are visible to the lints; they differ only in whether the generated .env remembers what the environment said.

Writer Meaning On the next make dotenv
eb.setdefault machine fact a non-empty value in the process env is adopted and written back
eb.set run fact recomputed from BuildContext; whatever the process env said is discarded

setdefault is the operator-override contract: exporting a key changes it and the change persists. That persistence is why it MUST NOT carry a value an environment declares for a single run. Makefile exports BASH_ENV, so every make recipe sources .env — a value adopted once is re-exported into every later recipe and into every container that mounts the repo, and a per-run decision has silently become a property of the machine.

A key that some environment declares per run therefore MUST be written by a dedicated handler through eb.set. The exporting shell still wins for its own run, because load.sh preserves non-empty caller values when it sources .env; the file keeps the derived default. INFINITO_RUNNING_ON_GITHUB, INFINITO_CACHE_STACK and INFINITO_GHCR_MIRROR are written this way. Note the consequence: for those keys .env and the running shell can legitimately disagree, and .env is not the authority.

Import Rules 🔗

  • parser.py, runtime.py, and writer.py MUST NOT import from builder.py or handlers/.
  • builder.py MUST NOT import individual handler modules; it MUST go through the ORDERED_HANDLERS list exposed by handlers/__init__.py.
  • Handler modules MUST NOT import each other (see handlers README).