Files
computer-playbook/cli/administration/deploy/development/profile.py
T
kevinveenbirkenbachandClaude Opus 5 3781c30235 fix(env): write the cache-stack declaration from a handler, not the registry
48845db97 made three capability decisions declarable and named them INFINITO_*, which put them under setdefault: the live environment wins and the value is written back. Makefile exports BASH_ENV, so .env is re-exported into every make recipe, and scripts/tests/code/run.sh reaches dotenv through 'make setup' on every test run. A declaration made for one run therefore became a machine fact on first regeneration and stayed one - that is what made the workspace failure intermittent rather than reproducible, and why fedora died on 11 assertions where debian passed the same code.

A dedicated handler writing through eb.set recomputes the value every time and discards whatever the environment held, so the key stays registered in default.env and visible to the lints while remaining structurally unpinnable. running_on/github.py already worked this way; the distinction now has a name in utils/env/README.md. The exporting shell still steers its own run, because load.sh preserves non-empty caller values.

The other two declarations are deleted rather than moved. image_mirror_enabled and docker_root_ephemeral both derive from runs_on_github(), and the orchestrator does not unset INFINITO_RUNNING_ON_GITHUB, so inside the workspace they were already true and the declarations restated a value that held anyway. Measured across all four runtime contexts: only the workspace row changes, and only for the cache.

Verified by reversing the probe: 'INFINITO_CACHE_STACK=false make dotenv' writes .env=true, where the registry path wrote the exported value back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 23:24:15 +02:00

67 lines
2.5 KiB
Python

"""Runtime-context helpers for the dev/CI compose stack."""
from __future__ import annotations
import os
def _declared(name: str) -> bool | None:
"""Explicit capability declaration, or None when it is left to the default."""
raw = (os.environ.get(name) or "").strip()
if raw == "true":
return True
if raw == "false":
return False
return None
class Profile:
"""Runtime identity and the capability decisions derived from it."""
def is_ci(self) -> bool:
"""True when any standard CI signal is set."""
return (
os.environ.get("GITHUB_ACTIONS") == "true"
or os.environ.get("INFINITO_RUNNING_ON_GITHUB") == "true"
or os.environ.get("CI") == "true"
)
def runs_on_github(self) -> bool:
"""True on a real GitHub runner; act and generic CI are not that."""
return os.environ.get("INFINITO_RUNNING_ON_GITHUB") == "true"
def cache_stack_enabled(self) -> bool:
"""True iff the pull-through cache stack should be loaded."""
declared = _declared("INFINITO_CACHE_STACK")
return (not self.is_ci()) if declared is None else declared
def image_mirror_enabled(self) -> bool:
"""True iff image references should be rewritten to the GHCR mirror."""
return self.runs_on_github()
def docker_root_ephemeral(self) -> bool:
"""True iff the docker data root may be wiped when the stack goes down."""
return self.runs_on_github()
def instance(self) -> int:
"""Slot index of this checkout; 0 is the primary one.
Bookkeeping only: the compose layering below keys off the concrete
resources a worktree was handed, never off this number, so a stray
slot cannot make compose demand a value nobody set.
"""
raw = (os.environ.get("INFINITO_INSTANCE") or "0").strip()
return int(raw) if raw.isdigit() else 0
def shared_git_dir(self) -> str:
"""Path of the checkout's shared .git directory, empty when it owns one."""
return (os.environ.get("INFINITO_GIT_COMMON_DIR") or "").strip()
def shared_cache_network(self) -> str:
"""Docker network of a cache stack owned elsewhere, empty when unset."""
return (os.environ.get("INFINITO_CACHE_NETWORK") or "").strip()
def owns_cache_stack(self) -> bool:
"""True iff this instance runs the cache stack rather than sharing it."""
return self.cache_stack_enabled() and not self.shared_cache_network()