Files
kandev/.github/scripts/update-agent-runtime-pins-workflow-contract_test.py
2026-09-04 14:33:41 +00:00

123 lines
5.6 KiB
Python

#!/usr/bin/env python3
"""Contract tests for the managed runtime pin update workflow."""
from pathlib import Path
import re
import unittest
REPO_ROOT = Path(__file__).resolve().parents[2]
WORKFLOW = REPO_ROOT / ".github" / "workflows" / "update-agent-runtime-pins.yml"
LINT_WORKFLOW = REPO_ROOT / ".github" / "workflows" / "lint-action-pinning.yml"
SCRIPT = REPO_ROOT / "scripts" / "update-agent-runtime-pins.mjs"
REQUIRED_CHECK_WORKFLOWS = (
"backend-tests.yml",
"frontend-tests.yml",
"e2e-tests.yml",
"architecture-lint.yml",
"lint-action-pinning.yml",
"lint-harness-files.yml",
)
class ManagedRuntimePinWorkflowContractTest(unittest.TestCase):
def setUp(self) -> None:
self.workflow = WORKFLOW.read_text(encoding="utf-8")
def test_workflow_has_weekly_and_manual_triggers(self) -> None:
self.assertIn("schedule:", self.workflow)
self.assertRegex(self.workflow, r"cron:\s*[\"']?[0-9]+ [0-9]+ \* \* [0-6][\"']?")
self.assertIn("workflow_dispatch:", self.workflow)
def test_workflow_uses_least_privilege_and_builtin_token(self) -> None:
self.assertIn(
"permissions:\n contents: write\n pull-requests: write", self.workflow
)
self.assertIn("GH_TOKEN: ${{ github.token }}", self.workflow)
self.assertNotIn("actions/create-github-app-token@", self.workflow)
self.assertNotIn("MANAGED_RUNTIME_PIN_APP_PRIVATE_KEY", self.workflow)
self.assertNotIn("MANAGED_RUNTIME_PIN_APP_CLIENT_ID", self.workflow)
self.assertNotIn("secrets.GITHUB_TOKEN", self.workflow)
def test_workflow_groups_one_conventional_commit_pr_on_stable_branch(self) -> None:
self.assertIn("update-managed-runtime-pins", self.workflow)
self.assertIn("chore: update managed runtime pins", self.workflow)
self.assertIn("gh pr create", self.workflow)
self.assertNotIn("gh pr merge", self.workflow)
self.assertNotIn("--auto", self.workflow)
self.assertIn("at most one", self.workflow)
def test_workflow_refreshes_existing_pr_by_number_and_authenticates_push(self) -> None:
self.assertIn('open_pr_number="$(gh pr list', self.workflow)
self.assertIn('gh pr edit "$open_pr_number"', self.workflow)
self.assertNotIn('gh pr edit \\\n --repo "$GITHUB_REPOSITORY" \\\n --head "$BOT_BRANCH"', self.workflow)
push_start = self.workflow.index("- name: Commit and push one grouped change")
pr_start = self.workflow.index("- name: Create or refresh the single grouped PR")
push_step = self.workflow[push_start:pr_start]
pr_step = self.workflow[pr_start:]
self.assertIn("GH_TOKEN: ${{ github.token }}", push_step)
self.assertIn("GH_TOKEN: ${{ github.token }}", pr_step)
def test_workflow_dispatches_required_checks_for_builtin_token_prs(self) -> None:
self.assertIn("actions: write", self.workflow)
dispatch_start = self.workflow.index(
"- name: Dispatch required checks for generated PR"
)
dispatch_step = self.workflow[dispatch_start:]
self.assertIn("gh workflow run", dispatch_step)
self.assertIn('--ref "$BOT_BRANCH"', dispatch_step)
self.assertIn('--repo "$GITHUB_REPOSITORY"', dispatch_step)
for workflow_name in REQUIRED_CHECK_WORKFLOWS:
self.assertIn(workflow_name, dispatch_step)
workflow = (REPO_ROOT / ".github" / "workflows" / workflow_name).read_text(
encoding="utf-8"
)
self.assertRegex(
workflow,
r"(?m)^ workflow_dispatch:\s*$",
f"{workflow_name} must accept explicit validation dispatches",
)
def test_workflow_validates_before_any_commit_or_push(self) -> None:
update_pos = self.workflow.index("node scripts/update-agent-runtime-pins.mjs")
validation_pos = self.workflow.index("go test ./internal/agent/agents")
commit_pos = self.workflow.index("git commit")
push_pos = self.workflow.index("git push")
self.assertLess(update_pos, validation_pos)
self.assertLess(validation_pos, commit_pos)
self.assertLess(commit_pos, push_pos)
self.assertIn("node --test scripts/update-agent-runtime-pins.test.mjs", self.workflow)
self.assertIn("--github-output", self.workflow)
self.assertIn("working-directory: apps/backend", self.workflow)
self.assertIn(
"go test ./internal/agent/agents ./internal/agent/managedruntime "
"./internal/agent/runtime/lifecycle ./internal/agent/hostutility "
"./internal/agent/settings/controller ./internal/agent/settings/handlers",
self.workflow,
)
self.assertIn("if: steps.update.outputs.changed == 'true'", self.workflow)
def test_all_actions_are_commit_pinned(self) -> None:
for line in self.workflow.splitlines():
if " uses: " not in line:
continue
self.assertRegex(line, r"uses:\s+[^@\s]+@[0-9a-f]{40}(?:\s+#.*)?$")
def test_lint_workflow_runs_this_contract(self) -> None:
lint_workflow = LINT_WORKFLOW.read_text(encoding="utf-8")
self.assertIn(
"python3 .github/scripts/update-agent-runtime-pins-workflow-contract_test.py",
lint_workflow,
)
def test_updater_script_exists_and_has_no_network_in_fixture_tests(self) -> None:
self.assertTrue(SCRIPT.is_file())
script = SCRIPT.read_text(encoding="utf-8")
self.assertIn("registry.npmjs.org", script)
self.assertIn("fs.rename", script)
if __name__ == "__main__":
unittest.main()