From 0168dd3be83f375c1508916b5b17853867ca8fd7 Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Wed, 23 Sep 2026 08:04:21 +0100 Subject: [PATCH] fix(ci): freeze reviewed action pins from Dependabot version updates action_consumer_manifests.json pins each release-consumed action to an exact SHA plus the upstream action.yml sha256, and release_promotion_policy_test.py requires every workflow step to match. Dependabot's github-actions group bumps those SHAs, so every group proposal fails the manifest contract and cannot be repaired offline. Ignore the eight governed actions for version updates and guard the policy against the manifest so pin refreshes stay explicit reviewed work. This resolves the recurring failing actions-minor-patch proposal (#2139). Change-source: pulse-maintainer --- .github/dependabot.yml | 15 +++++++++++++++ scripts/tests/test_dependabot_config.py | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d82bd615dc..524fe6c9d0 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -23,6 +23,21 @@ updates: update-types: - "minor" - "patch" + # scripts/release_control/action_consumer_manifests.json pins each + # release-consumed action to an exact SHA plus the upstream action.yml + # sha256, and release_promotion_policy_test.py requires every workflow step + # to match that manifest. Refreshing a pin needs the upstream action bytes + # through the reviewed pin-refresh route, so keep these actions as explicit + # work rather than opening proposals the manifest contract cannot accept. + ignore: + - dependency-name: "actions/attest" + - dependency-name: "azure/setup-helm" + - dependency-name: "docker/build-push-action" + - dependency-name: "docker/login-action" + - dependency-name: "docker/setup-buildx-action" + - dependency-name: "docker/setup-qemu-action" + - dependency-name: "signpath/github-action-submit-signing-request" + - dependency-name: "tailscale/github-action" - package-ecosystem: "gomod" directories: diff --git a/scripts/tests/test_dependabot_config.py b/scripts/tests/test_dependabot_config.py index 2052a3af9b..8aba5d798d 100644 --- a/scripts/tests/test_dependabot_config.py +++ b/scripts/tests/test_dependabot_config.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """Guard the low-noise dependency update policy and its covered manifests.""" +import json from pathlib import Path import unittest @@ -10,6 +11,7 @@ import yaml ROOT = Path(__file__).resolve().parents[2] CONFIG = ROOT / ".github" / "dependabot.yml" SECURITY_SCAN = ROOT / ".github" / "workflows" / "security-scan.yml" +ACTION_MANIFESTS = ROOT / "scripts" / "release_control" / "action_consumer_manifests.json" def manifest_directories(filename: str) -> list[str]: @@ -159,6 +161,20 @@ class DependabotConfigTest(unittest.TestCase): {"version-update:semver-major"}, ) + def test_github_actions_updates_preserve_reviewed_action_pins(self) -> None: + # action_consumer_manifests.json pins each release-consumed action to an + # exact SHA plus the upstream action.yml sha256, and + # release_promotion_policy_test.py requires every workflow step to match + # it. Refreshing a pin needs the upstream bytes through the reviewed + # pin-refresh route, so Dependabot must not propose version updates the + # manifest contract would reject. + manifests = json.loads(ACTION_MANIFESTS.read_text(encoding="utf-8")) + ignored = { + item["dependency-name"] + for item in self.updates["github-actions"]["ignore"] + } + self.assertEqual(ignored, set(manifests)) + def test_weekly_scan_covers_the_same_lockfiles(self) -> None: workflow = yaml.safe_load(SECURITY_SCAN.read_text(encoding="utf-8")) jobs = workflow["jobs"]