diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 237e6bf29..8bd3e97b9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,6 +4,8 @@ updates: directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 7 groups: github-actions: patterns: @@ -13,6 +15,8 @@ updates: directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 7 groups: docker-base-images: patterns: @@ -22,6 +26,8 @@ updates: directory: "/frontend" schedule: interval: "weekly" + cooldown: + default-days: 7 groups: frontend-docker-base-images: patterns: @@ -31,6 +37,8 @@ updates: directory: "/backend" schedule: interval: "weekly" + cooldown: + default-days: 7 groups: backend-python: patterns: @@ -40,6 +48,8 @@ updates: directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 7 groups: ci-python: patterns: @@ -49,6 +59,8 @@ updates: directory: "/frontend" schedule: interval: "weekly" + cooldown: + default-days: 7 groups: frontend-npm: patterns: @@ -58,13 +70,12 @@ updates: directory: /connector schedule: interval: daily + cooldown: + default-days: 7 - package-ecosystem: pip directory: /connector schedule: interval: daily - - - package-ecosystem: npm - directory: / - schedule: - interval: daily + cooldown: + default-days: 7 diff --git a/backend/tests/test_release_governance.py b/backend/tests/test_release_governance.py index 0eb430cc2..0d5637a9e 100644 --- a/backend/tests/test_release_governance.py +++ b/backend/tests/test_release_governance.py @@ -306,6 +306,46 @@ def construct_mapping( assert duplicates == [], "\n".join(duplicates) +def test_dependabot_npm_directories_contain_package_manifests() -> None: + """Keep npm update jobs bound to directories that Dependabot can inspect.""" + dependabot_config = yaml.safe_load(read_repo_text(".github/dependabot.yml")) + + npm_directories = [ + update["directory"] + for update in dependabot_config["updates"] + if update["package-ecosystem"] == "npm" + ] + + assert npm_directories, "Dependabot must track at least one npm workspace" + missing_manifests = [ + directory + for directory in npm_directories + if not ( + REPO_ROOT / directory.removeprefix("/") / "package.json" + ).is_file() + ] + assert missing_manifests == [], ( + "Dependabot npm directories must contain package.json: " + + ", ".join(missing_manifests) + ) + + +def test_dependabot_updates_enforce_supply_chain_cooldown() -> None: + """Hold newly published dependency versions for a review observation window.""" + updates = yaml.safe_load(read_repo_text(".github/dependabot.yml"))["updates"] + + assert len(updates) == 8 + missing_or_short = [ + f"{update['package-ecosystem']}:{update['directory']}" + for update in updates + if (update.get("cooldown") or {}).get("default-days", 0) < 7 + ] + assert missing_or_short == [], ( + "Dependabot updates require at least a seven-day cooldown: " + + ", ".join(missing_or_short) + ) + + def test_stepsecurity_remediation_adds_pinned_audit_hardening() -> None: harden_runner_ref = ( "step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0"