From b853106455fc542acb672a0f22d262f67042b9eb Mon Sep 17 00:00:00 2001 From: Tim Stranske Date: Tue, 16 Jun 2026 23:26:14 -0500 Subject: [PATCH 1/2] test: lock dependency bot condition hardening --- .../workflows/maint-auto-label-dep-prs.yml | 3 ++ .github/workflows/maint-auto-lock-deps.yml | 5 +++ .../test_dependency_bot_conditions.py | 41 +++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 tests/workflows/test_dependency_bot_conditions.py diff --git a/.github/workflows/maint-auto-label-dep-prs.yml b/.github/workflows/maint-auto-label-dep-prs.yml index 5c0b8d095..a1264a498 100644 --- a/.github/workflows/maint-auto-label-dep-prs.yml +++ b/.github/workflows/maint-auto-label-dep-prs.yml @@ -4,6 +4,7 @@ name: Auto-label dependency PRs # became the fleet's bumper; not a gate check, so the check-run rename is safe. on: + # zizmor: ignore[dangerous-triggers] labels dependency-bot PRs only; does not checkout or run PR code pull_request_target: types: [opened] @@ -17,6 +18,8 @@ concurrency: jobs: label: # Dependabot and Renovate both produce dependency PRs that should carry agents:allow-change. + # This pull_request_target workflow must trust the immutable PR author, not + # github.actor, because actor can be a maintainer rerunning a bot-authored PR. if: github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'renovate[bot]' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/maint-auto-lock-deps.yml b/.github/workflows/maint-auto-lock-deps.yml index 3c450f4e4..449facda4 100644 --- a/.github/workflows/maint-auto-lock-deps.yml +++ b/.github/workflows/maint-auto-lock-deps.yml @@ -32,9 +32,14 @@ jobs: regenerate-lock: name: Regenerate requirements.lock runs-on: ubuntu-latest + # This workflow runs on pull_request, not pull_request_target, so checking + # out github.head_ref is not an untrusted-code privileged checkout. + # Gate on the immutable PR author rather than github.actor, which can be a + # maintainer rerunning a bot-authored PR. if: github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'renovate[bot]' steps: + # zizmor: ignore[artipacked] this backstop intentionally pushes regenerated requirements.lock - uses: actions/checkout@v6 with: ref: ${{ github.head_ref }} diff --git a/tests/workflows/test_dependency_bot_conditions.py b/tests/workflows/test_dependency_bot_conditions.py new file mode 100644 index 000000000..4488fc253 --- /dev/null +++ b/tests/workflows/test_dependency_bot_conditions.py @@ -0,0 +1,41 @@ +import pathlib + +import yaml + + +WORKFLOW_ROOT = pathlib.Path(".github/workflows") +SYNC_MANIFEST = pathlib.Path(".github/sync-manifest.yml") +ACTIVE_DEPENDENCY_BOT_WORKFLOWS = ( + WORKFLOW_ROOT / "maint-auto-label-dep-prs.yml", + WORKFLOW_ROOT / "maint-auto-lock-deps.yml", +) +RETIRED_CONSUMER_AUTOMERGE = pathlib.Path( + "templates/consumer-repo/.github/workflows/dependabot-automerge.yml" +) + + +def _workflow_source(path: pathlib.Path) -> str: + assert path.exists(), f"Expected workflow file to exist: {path}" + return path.read_text(encoding="utf-8") + + +def test_dependency_bot_workflows_gate_on_pr_author_not_trigger_actor(): + for workflow in ACTIVE_DEPENDENCY_BOT_WORKFLOWS: + source = _workflow_source(workflow) + assert "github.event.pull_request.user.login" in source + assert "github.actor == 'dependabot[bot]'" not in source + assert "github.actor == 'renovate[bot]'" not in source + + +def test_auto_lock_documents_pull_request_head_ref_trust_boundary(): + source = _workflow_source(WORKFLOW_ROOT / "maint-auto-lock-deps.yml") + assert "pull_request, not pull_request_target" in source + assert "github.head_ref is not an untrusted-code privileged checkout" in source + + +def test_retired_consumer_dependabot_automerge_template_stays_removed(): + assert not RETIRED_CONSUMER_AUTOMERGE.exists() + + manifest = yaml.safe_load(SYNC_MANIFEST.read_text(encoding="utf-8")) or {} + removal_targets = {entry.get("target") for entry in manifest.get("removals", [])} + assert ".github/workflows/dependabot-automerge.yml" in removal_targets From a1a33cc1496ee406463d2fda501e9777b6a11bd9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 17 Jun 2026 04:39:04 +0000 Subject: [PATCH 2/2] chore(autofix): formatting/lint --- tests/workflows/test_dependency_bot_conditions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/workflows/test_dependency_bot_conditions.py b/tests/workflows/test_dependency_bot_conditions.py index 4488fc253..2b798f632 100644 --- a/tests/workflows/test_dependency_bot_conditions.py +++ b/tests/workflows/test_dependency_bot_conditions.py @@ -2,7 +2,6 @@ import yaml - WORKFLOW_ROOT = pathlib.Path(".github/workflows") SYNC_MANIFEST = pathlib.Path(".github/sync-manifest.yml") ACTIVE_DEPENDENCY_BOT_WORKFLOWS = (