shoc-frontend-new/scripts/test-hcp-run-guard.py

244 lines
7.4 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""Tests for every hcp-run-guard refusal, exit-0, discard, and reconcile case."""
from __future__ import annotations
import importlib.util
from pathlib import Path
from typing import Any
SCRIPT = Path(__file__).with_name("hcp-run-guard.py")
WORKSPACE = "shoc-frontend-new-dev"
PATTERNS = [
"terraform/live/dev/**",
"terraform/live/modules/**",
]
def load_module():
spec = importlib.util.spec_from_file_location("hcp_run_guard", SCRIPT)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
return module
def workspace_payload(
*,
auto_apply: bool = False,
speculative: bool = True,
tags_regex: str | None = None,
trigger_patterns: list[str] | None = None,
locked: bool = False,
current_run: dict[str, Any] | None = None,
) -> dict[str, Any]:
return {
"data": {
"attributes": {
"auto-apply": auto_apply,
"speculative-enabled": speculative,
"vcs-repo": {"tags-regex": tags_regex},
"trigger-patterns": PATTERNS if trigger_patterns is None else trigger_patterns,
"locked": locked,
},
"relationships": {
"current-run": {"data": current_run},
},
}
}
def run_payload(*, status: str, plan_only: bool = False) -> dict[str, Any]:
return {"data": {"attributes": {"status": status, "plan-only": plan_only}}}
def check(module, payloads: dict[str, Any], posts: list | None = None):
calls: list[str] = []
def get(url: str) -> dict[str, Any]:
calls.append(url)
if url not in payloads:
raise AssertionError(f"unexpected GET {url}")
return payloads[url]
recorded: list[tuple[str, dict[str, Any]]] = []
def post(url: str, payload: dict[str, Any]) -> int:
recorded.append((url, payload))
if posts:
return posts.pop(0)
return 202
try:
code = module.check_and_discard(
workspace=WORKSPACE,
token="test-token",
get=get,
post=post,
)
return code, None, calls, recorded
except module.GuardError as exc:
return 1, str(exc), calls, recorded
def reconcile(module, outcome: str, payloads: dict[str, Any], run_id: str = "run-1"):
def get(url: str) -> dict[str, Any]:
if url not in payloads:
raise AssertionError(f"unexpected GET {url}")
return payloads[url]
try:
code = module.reconcile_apply(
run_id=run_id,
apply_outcome=outcome,
token="test-token",
get=get,
)
return code, None
except module.GuardError as exc:
return 1, str(exc)
def main() -> int:
module = load_module()
ws = f"https://app.terraform.io/api/v2/organizations/seahaven/workspaces/{WORKSPACE}"
run_url = "https://app.terraform.io/api/v2/runs/run-1"
discard_url = f"{run_url}/actions/discard"
failures: list[str] = []
def expect_refuse(name: str, payloads: dict[str, Any], fragment: str) -> None:
code, error, _, recorded = check(module, payloads)
if code != 1 or not error or fragment not in error:
failures.append(f"{name}: expected refuse containing {fragment!r}, got {code} {error}")
if recorded:
failures.append(f"{name}: discard was posted on a refusal")
expect_refuse(
"auto-apply",
{ws: workspace_payload(auto_apply=True)},
"auto-apply is on",
)
expect_refuse(
"speculative-off",
{ws: workspace_payload(speculative=False)},
"speculative plans are off",
)
expect_refuse(
"tags-regex",
{ws: workspace_payload(tags_regex="^v")},
"tag-based VCS triggering",
)
expect_refuse(
"wrong-patterns",
{ws: workspace_payload(trigger_patterns=["terraform/**"])},
"trigger-patterns must be",
)
expect_refuse(
"locked-without-run",
{ws: workspace_payload(locked=True, current_run=None)},
"locked without a current run",
)
expect_refuse(
"applying",
{
ws: workspace_payload(locked=True, current_run={"id": "run-1"}),
run_url: run_payload(status="applying"),
},
"wait, do not discard an apply",
)
expect_refuse(
"not-discardable",
{
ws: workspace_payload(locked=True, current_run={"id": "run-1"}),
run_url: run_payload(status="errored"),
},
"is not discardable",
)
code, error, _, recorded = check(module, {ws: workspace_payload(locked=False)})
if code != 0 or error is not None or recorded:
failures.append(f"unlocked: expected exit 0, got {code} {error} {recorded}")
code, error, _, recorded = check(
module,
{
ws: workspace_payload(locked=True, current_run={"id": "run-1"}),
run_url: run_payload(status="planned", plan_only=True),
},
)
if code != 0 or recorded:
failures.append(f"plan-only: expected exit 0 without discard, got {code} {recorded}")
code, error, _, recorded = check(
module,
{
ws: workspace_payload(locked=True, current_run={"id": "run-1"}),
run_url: run_payload(status="planned"),
},
)
if code != 0 or error is not None:
failures.append(f"discard: expected exit 0, got {code} {error}")
if not recorded or recorded[0][0] != discard_url:
failures.append(f"discard: posted {recorded}")
code, error, _, recorded = check(
module,
{
ws: workspace_payload(locked=True, current_run={"id": "run-1"}),
run_url: run_payload(status="policy_checked"),
},
posts=[409],
)
if code != 0:
failures.append(f"discard-409: expected exit 0, got {code} {error}")
try:
module.check_and_discard(workspace=WORKSPACE, token="", get=lambda _url: {})
failures.append("missing-token: accepted empty token")
except module.GuardError:
pass
code, error = reconcile(module, "success", {})
if code != 0:
failures.append(f"reconcile-success: expected 0, got {code} {error}")
code, error = reconcile(
module,
"failure",
{run_url: run_payload(status="applied")},
)
if code != 0:
failures.append(f"reconcile-applied: expected 0, got {code} {error}")
code, error = reconcile(
module,
"failure",
{run_url: run_payload(status="errored")},
)
if code != 1 or not error or "errored" not in error:
failures.append(f"reconcile-errored: expected refuse, got {code} {error}")
try:
module.reconcile_apply(run_id="", apply_outcome="failure", token="test-token")
failures.append("reconcile-missing-run: accepted empty run id")
except module.GuardError:
pass
try:
module.reconcile_apply(run_id="run-1", apply_outcome="failure", token="")
failures.append("reconcile-missing-token: accepted empty token")
except module.GuardError:
pass
if failures:
print("FAIL: hcp-run-guard cases failed", file=__import__("sys").stderr)
for item in failures:
print(f" - {item}", file=__import__("sys").stderr)
return 1
print("PASS: HCP run guard checks")
return 0
if __name__ == "__main__":
raise SystemExit(main())