From 64a7f3dc9638d6c0a35ac831a515230b21ce60f2 Mon Sep 17 00:00:00 2001 From: svonava Date: Mon, 19 Oct 2026 15:49:33 -0700 Subject: [PATCH] ci: limit policy setup to its pinned tools --- .github/workflows/ci.yml | 9 ++++---- tools/ci/tests/test_required_ci.py | 33 ++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e689b255f..efb12fb0a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,17 +21,18 @@ jobs: - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 with: persist-credentials: false + # Keep the same explicit selection in every exec below to avoid lazy tool installs. - uses: jdx/mise-action@c37c93293d6b742fc901e1406b8f764f6fb19dac # v2 with: version: 2026.5.5 - install_args: --jobs=1 + install_args: --jobs=1 python uv github:rhysd/actionlint cache: false - run: >- - mise exec -- uv run --frozen --project . pytest -q + mise exec --no-deps python uv github:rhysd/actionlint -- uv run --frozen --project . pytest -q tools/ci/tests/test_required_ci.py tools/ci/tests/test_public_tree.py - - run: mise exec -- python tools/ci/check_public_tree.py + - run: mise exec --no-deps python uv github:rhysd/actionlint -- python tools/ci/check_public_tree.py - run: >- - mise exec -- actionlint + mise exec --no-deps python uv github:rhysd/actionlint -- actionlint -ignore '^unexpected key "queue" for "concurrency" section\. expected one of "cancel-in-progress", "group"$' bootstrap: diff --git a/tools/ci/tests/test_required_ci.py b/tools/ci/tests/test_required_ci.py index 513243cb9..48b6ee68c 100644 --- a/tools/ci/tests/test_required_ci.py +++ b/tools/ci/tests/test_required_ci.py @@ -100,8 +100,8 @@ def test_mise_workflow_setups_pin_concrete_versions(): ) -def test_mise_bootstrap_serializes_the_complete_toolset(): - # Partial installs defer the other tools to `mise exec`, outside install_args. +def test_mise_bootstrap_serializes_required_toolsets(): + # Unqualified `mise exec` installs missing tools outside install_args. for path in sorted((ROOT / ".github/workflows").glob("*.y*ml")): workflow = yaml.safe_load(path.read_text()) for name, job in workflow["jobs"].items(): @@ -110,11 +110,36 @@ def test_mise_bootstrap_serializes_the_complete_toolset(): continue inputs = step.get("with", {}) if inputs.get("install", True) is not False: - assert shlex.split(inputs.get("install_args", "")) == ["--jobs=1"], ( - f"{path.name}: {name} must serialize the full tool install to avoid Node GPG races" + expected = ["--jobs=1"] + if path.name == "ci.yml" and name == "policy": + expected += ["python", "uv", "github:rhysd/actionlint"] + assert shlex.split(inputs.get("install_args", "")) == expected, ( + f"{path.name}: {name} must serialize its tool install to avoid Node GPG races" ) +def test_policy_exec_does_not_lazily_install_unrelated_tools(): + workflow = yaml.safe_load((ROOT / ".github/workflows/ci.yml").read_text()) + policy = workflow["jobs"]["policy"] + commands = [shlex.split(step["run"]) for step in policy["steps"] if "run" in step] + prefix = ["mise", "exec", "--no-deps", "python", "uv", "github:rhysd/actionlint", "--"] + assert len(commands) == 3 + assert all(command[: len(prefix)] == prefix for command in commands) + assert commands[0][len(prefix) :] == [ + "uv", + "run", + "--frozen", + "--project", + ".", + "pytest", + "-q", + "tools/ci/tests/test_required_ci.py", + "tools/ci/tests/test_public_tree.py", + ] + assert commands[1][len(prefix) :] == ["python", "tools/ci/check_public_tree.py"] + assert commands[2][len(prefix)] == "actionlint" + + @pytest.mark.parametrize("install_status", [0, 1]) def test_init_serializes_install_and_stops_on_failure(tmp_path, install_status): log = tmp_path / "mise.log"