From 57ca90c58e26c30d779e78dc5f7b29c36e8a7662 Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Thu, 22 Oct 2026 13:29:17 +0000 Subject: [PATCH] security: approve fixed trust bootstrap and crates OIDC action --- qualification/policy.json | 6 ++++++ scripts/qualification_policy.py | 10 ++++++++++ tests/test_qualification_policy.py | 21 +++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/qualification/policy.json b/qualification/policy.json index 32521a1..56ec327 100644 --- a/qualification/policy.json +++ b/qualification/policy.json @@ -72,6 +72,9 @@ "4cda84d5c5c54efe2404f9d843567869ab1699d4": "stable", "4d407b29186a635f0cc27475ef0bc0ae605a8866": "1.86.0" }, + "durable-workflow/.github": { + "ff93e15dd3d3aa0b5ba8991fe5101a9e1be49c10": "patched-pip" + }, "helm/chart-testing-action": { "6ec842c01de15ebb84c8627d2744a0c2f2755c9f": "v2.8.0" }, @@ -84,6 +87,9 @@ "pypa/gh-action-pypi-publish": { "ba38be9e461d3875417946c167d0b5f3d385a247": "release/v1" }, + "rust-lang/crates-io-auth-action": { + "c6f97d42243bad5fab37ca0427f495c86d5b1a18": "v1.0.5" + }, "shivammathur/setup-php": { "f3e473d116dcccaddc5834248c87452386958240": "v2", "eb7c497e18156a6bbabfef1d3a82760b9eda3962": "v2.40.0" diff --git a/scripts/qualification_policy.py b/scripts/qualification_policy.py index 7669d94..77c5ecb 100644 --- a/scripts/qualification_policy.py +++ b/scripts/qualification_policy.py @@ -708,6 +708,16 @@ def _verify_action_policy_preflight( raise PolicyError(f"{label} central action policy preflight job is not the reviewed read-only shape") steps = preflight.get("steps") + if isinstance(steps, list) and len(steps) == 6: + bootstrap = steps[3] + if ( + not isinstance(bootstrap, dict) + or set(bootstrap) - {"name", "uses"} + or bootstrap.get("uses") + != "durable-workflow/.github/.github/actions/bootstrap-patched-pip@ff93e15dd3d3aa0b5ba8991fe5101a9e1be49c10" + ): + raise PolicyError(f"{label} central action policy preflight has an unreviewed pip bootstrap") + steps = steps[:3] + steps[4:] if not isinstance(steps, list) or len(steps) != 5 or not all(isinstance(step, dict) for step in steps): raise PolicyError(f"{label} central action policy preflight must contain the five reviewed steps") candidate, central, setup_python, install, validate = steps diff --git a/tests/test_qualification_policy.py b/tests/test_qualification_policy.py index ddf9a16..ccdeb55 100644 --- a/tests/test_qualification_policy.py +++ b/tests/test_qualification_policy.py @@ -124,6 +124,27 @@ def test_policy_preflight_accepts_binary_only_without_relaxing_dependency_comman jobs["action-policy"]["steps"][3]["run"] = "python -m pip install --only-binary :all: PyYAML" + suffix _verify_action_policy_preflight("ai", "fixture", jobs, "gate") + steps = jobs["action-policy"]["steps"] + steps[3]["run"] = "python -m pip install PyYAML==6.0.2" + bootstrap = { + "name": "Bootstrap patched pip trust", + "uses": "durable-workflow/.github/.github/actions/bootstrap-patched-pip@ff93e15dd3d3aa0b5ba8991fe5101a9e1be49c10", + } + steps.insert(3, bootstrap) + _verify_action_policy_preflight("ai", "fixture", jobs, "gate") + for change in ( + {**bootstrap, "uses": bootstrap["uses"].replace("ff93e15", "0000000")}, + {**bootstrap, "if": "false"}, + {"run": "python -m pip install --upgrade pip"}, + ): + with self.subTest(bootstrap=change), self.assertRaisesRegex(PolicyError, "unreviewed pip bootstrap"): + steps[3] = change + _verify_action_policy_preflight("ai", "fixture", jobs, "gate") + steps[3] = bootstrap + steps[3], steps[4] = steps[4], steps[3] + with self.assertRaisesRegex(PolicyError, "unreviewed pip bootstrap"): + _verify_action_policy_preflight("ai", "fixture", jobs, "gate") + def test_approved_immutable_action_with_version_comment_is_accepted(self) -> None: commit, version = self.approved_action("actions/checkout") evidence = self.scan(workflow(f"- uses: actions/checkout@{commit} # {version}"))