Closes the gap left by test_image_versions, which silently skips any
non-semver pin (latest, stable, branch tags). The new test_image_reachable
walks every entry from iter_role_images and probes the Docker Registry v2
manifest endpoint via HTTPS with anonymous bearer-token negotiation
(docker.io, ghcr.io, quay.io, mcr.microsoft.com). HTTP 404 hard-fails as
a broken pin; auth/rate-limit/5xx/network errors warn. Bounded by per-
request, per-probe, and global deadlines and parallelized via
INFINITO_WORKER_FETCH.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three new lint tests close gaps in the INFINITO_* SPOT contract:
* tests/lint/filesystem/env/test_default_env_keys_handled.py
Every default.env key must be wired through a handler.
* tests/lint/filesystem/env/test_used_keys_declared.py
Every INFINITO_* in .sh/.py must live in env/{default,ci}.env or
a handler; per-line `# nocheck:` suppresses runtime-only refs.
* tests/lint/filesystem/python/test_no_infinito_get_defaults.py
Forbid ANY default in `.get("INFINITO_*", ...)` -- including the
empty-string fallback (which silently masks an unset key). The
nocheck check walks every physical line the call spans so an
autoformat-split call still honours the marker.
Cache namespace flattens to a single prefix:
INFINITO_PACKAGE_CACHE_* -> INFINITO_CACHE_PACKAGE_*
INFINITO_REGISTRY_CACHE_* -> INFINITO_CACHE_REGISTRY_*
The five previously driver-injected paths (APT_LIST, NPMRC,
PIP_CONF, REGISTRY_PROXY_CONF, FRONTEND_CA_FILE) move into
env/default.env and passthrough.STATIC_KEYS; the
`cache_env_overrides()` helper and its two call sites are gone
along with the test-fixture override for FRONTEND_CA_DIR.
SPOT-strict rewrites:
- 19 sites: `something.get("INFINITO_X", "")` -> subscript
`something["INFINITO_X"]` (loud KeyError when env loader did
not run; all keys live in env/default.env).
- 2 handler-internal bootstrap reads suppressed with
`# nocheck: handler-bootstrap-read`.
- 30 runtime-only / driver-injected / test-fixture references
annotated with `# nocheck: <reason>` per-line.
- Unit tests that previously removed SPOT-guaranteed keys via
`{k: v ... if k \!= KEY}` or `clear=True` switch to setting
the key to "" explicitly, matching the new contract.
Side fixes:
- INFINITO_DNS_DOMAIN + INFINITO_DNS_HOSTS_FILE move from
shell-side defaults in common.sh to env/default.env and
passthrough.STATIC_KEYS.
- dns_systemd_is_operational() drops the dead
INFINITO_DNS_FORCE_HOSTS_FALLBACK override branch (the
variable was never set anywhere).
- INFINITO_WORKER_FETCH switches from `os.environ.get(KEY, "1")`
to `os.environ[KEY]`.
- scripts/tests/code/wrapper.sh exec args move into a bash
array so `# nocheck:` on INFINITO_TEST_TYPE can live on its
own element line (SC2215 fix).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rename INFINITO_PARALLEL -> INFINITO_WORKER_ENABLED and add two derived
keys so consumers no longer multiply by their own factor: the env
generator resolves the cascade once at `make dotenv` time and bakes
the integer counts into `.env`.
Chain:
- INFINITO_WORKER_ENABLED (operator toggle, default true)
- INFINITO_WORKER_CPU = cpu_count() when ENABLED truthy, else 1
- INFINITO_WORKER_FETCH = CPU * 20 for I/O-bound bulk fetches,
collapsing to 1 when CPU == 1
Handlers:
- utils/env/handlers/infinito_worker.py (the prior single key)
removed
- utils/env/handlers/infinito_worker_cpu.py + infinito_worker_fetch.py
added; registry orders them after `passthrough` so the cascade
reads its dependency from the env-builder state.
Consumers (now 1-liners):
- tests/external/repository/test_urls_reachable.py reads
INFINITO_WORKER_FETCH directly.
- utils/update/base.py::resolve_max_fetch_workers() reads it directly;
utils/update/{docker,repository}.py keep using that helper plus a
ThreadPoolExecutor for the actual bulk fetch (with `dict(pool.map(...))`
satisfying PERF403).
- scripts/lint/autoformat.sh + docs/contributing/tools/make.md
rename INFINITO_PARALLEL -> INFINITO_WORKER_ENABLED.
Tests:
- EXPECTED_BASELINE_KEYS in test_dotenv_generator updated to track the
three new keys.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add MCR_REGISTRY constant, is_mcr / mcr_repo / fetch_mcr_tags helpers
mirroring the Docker Hub and GHCR pattern. Tags are fetched via the
Docker Registry V2 API with RFC 5988 Link-header pagination (anonymous
access; MCR is a public read mirror). Wire MCR into both the external
test_image_versions warning surface and the find_outdated_updates
orchestrator in utils.update.docker.
- Bump mcr.microsoft.com/playwright in test-e2e-playwright from
v1.59.1-noble to v1.60.0-noble — the update was surfaced by the new
MCR detection path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds `test_semver_pinning.py` under `tests/lint/ansible/services/`.
Recursively walks every `roles/*/meta/services.yml`, surfaces a
warning for every `image:`+`version:` pair and every `repository:`+`ref:`
pair whose value is not semver-compatible. Output via the shared
annotations helper (GitHub Actions `::warning::` plus pytest's
`warnings.warn`), with a single trailing suppression hint when any
finding fires. Never fails the test session.
Suppression reuses the existing markers:
- `# nocheck: docker-version` for `version:` pins
- `# nocheck: repository-version` for `ref:` pins
Both accept same-line or line-above placement. The existing external
update checks (`utils/update/docker.suppressed_services` and
`utils/update/repository.suppressed_ref_lines`) are loosened from
strict `line-above` to the default `same-or-above` for consistent
marker semantics across all three consumers.
Updates `docs/contributing/actions/testing/suppression.md` so the
catalog lists both consumers per marker and adds the previously
missing `repository-version` row.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Folds the parallel Docker-image and git-ref version-update plumbing
into a single subsystem so the auto-update workflow, the external
freshness tests, and the unit tests all share one module layout.
utils/
update/
base.py # semver primitives shared by both backends
docker.py # OCI registry lookups + version: line rewriter
repository.py # git ls-remote walker + ref: line rewriter
cli/contributing/update/
docker/ # python -m cli.contributing.update.docker
repository/ # python -m cli.contributing.update.repository
scripts/github/update/
image_versions.sh
repository_refs.sh
Tests mirror the same shape under tests/{unit,external}/update/{docker,repository}/.
Also widens the Docker bump scope to all roles (previously gated on
`web-*`) so non-web roles like sys-svc-container get bumped too;
pins Bookwyrm's python image at 3.11-bookworm via
`# nocheck: docker-version` with a TODO until upstream supports
Python >= 3.12.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>