Files
computer-playbook/tests/unit/python/cli/meta/env/test_main.py
T
kevinveenbirkenbachandClaude Opus 5.5 e31b9557d2 fix(env): keep the host .env when the runner container runs make setup
The repository is bind-mounted into the infinito container, and every deploy
runs `make setup` there, which depends on `dotenv`. The generator therefore
rewrote the host's .env with the values the container sees: the host lost
INFINITO_RUNNING_ON_GITHUB=true that way, and the guide replay pulled
alpine:latest past the GHCR mirror.

compose.yml now marks the infinito service with INFINITO_DOTENV_HOST_OWNED,
and `python -m cli.meta.env` keeps an existing .env while that marker is
"true". A missing .env is still generated, and `make dotenv-force` (env -i)
still rewrites it. The key stays out of the env registry: only compose.yml
sets it, it is no configuration value, and a .env entry could freeze the
host .env.

test_distros now also strips INFINITO_ENV_LOADED. load.sh returns early
while that guard is set and the mtime of .env is unchanged, so the test only
reloaded the budget keys it strips because the container kept rewriting .env.

Verified: unit tests cover a kept .env, a missing one being generated, and a
rewrite without the marker. Local compose deploys print "Kept .env: the host
checkout owns it" where they printed "Wrote .env" before, the host .env
checksum stayed the same across a deploy, and the four keys holding host
paths resolve inside the container under the same paths.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 18:35:22 +02:00

46 lines
1.7 KiB
Python

from __future__ import annotations
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
import cli.meta.env.__main__ as env_main
class TestDotenvHostOwned(unittest.TestCase):
def _run(self, *, dotenv_exists: bool, host_owned: str | None) -> tuple[int, bool]:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
(root / "default.env").write_text("INFINITO_DISTRO=debian\n")
if dotenv_exists:
(root / ".env").write_text("INFINITO_RUNNING_ON_GITHUB=true\n")
environ = (
{} if host_owned is None else {env_main.HOST_OWNED_KEY: host_owned}
)
with (
patch.object(env_main, "REPO_ROOT", root),
patch.dict("os.environ", environ, clear=True),
patch.object(
env_main, "parse_static_env_with_comments", return_value=({}, {})
),
patch.object(env_main, "build_env") as build_env,
patch.object(env_main, "write_dotenv") as write_dotenv,
):
build_env.return_value.values = {}
rc = env_main.main()
return rc, write_dotenv.called
def test_a_host_owned_dotenv_is_kept(self) -> None:
self.assertEqual(self._run(dotenv_exists=True, host_owned="true"), (0, False))
def test_a_missing_dotenv_is_generated_even_when_host_owned(self) -> None:
self.assertEqual(self._run(dotenv_exists=False, host_owned="true"), (0, True))
def test_without_the_marker_the_dotenv_is_regenerated(self) -> None:
self.assertEqual(self._run(dotenv_exists=True, host_owned=None), (0, True))
if __name__ == "__main__": # pragma: no cover
unittest.main()