mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 13:03:12 +00:00
Some checks are pending
Validate and deploy / Validate deployable source bundle (push) Waiting to run
Validate and deploy / Deploy shoc-backend-dev through Terraform (push) Blocked by required conditions
Validate and deploy / Deploy shoc-backend-staging to Elastic Beanstalk (push) Blocked by required conditions
* feat(deploy): move dev application CD through Terraform GitHub creates the immutable Elastic Beanstalk version; HCP Terraform is the only UpdateEnvironment caller via a guarded version_label run. * fix: add permissions block for dependency-review workflow Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * fix(terraform): stop pinning the generated dev instance SG --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
295 lines
10 KiB
Python
295 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""Deterministic tests for check-terraform-release-plan.py."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import io
|
|
import subprocess
|
|
import sys
|
|
import urllib.request
|
|
from email.message import EmailMessage
|
|
from pathlib import Path
|
|
from urllib.request import Request
|
|
|
|
SCRIPT = Path(__file__).with_name("check-terraform-release-plan.py")
|
|
FIXTURES = Path(__file__).with_name("testdata") / "terraform-release-plans"
|
|
EXPECTED_LABEL = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-2-1"
|
|
PLAN_ID = "plan-8F5JFydVYAmtTjET"
|
|
|
|
|
|
def run_case(
|
|
fixture_name: str,
|
|
*,
|
|
expected_label: str = EXPECTED_LABEL,
|
|
) -> subprocess.CompletedProcess[str]:
|
|
return subprocess.run(
|
|
[
|
|
sys.executable,
|
|
str(SCRIPT),
|
|
str(FIXTURES / fixture_name),
|
|
"--expected-version-label",
|
|
expected_label,
|
|
],
|
|
check=False,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
|
|
class FakeResponse:
|
|
def __init__(
|
|
self,
|
|
*,
|
|
url: str,
|
|
status: int,
|
|
headers: dict[str, str] | None = None,
|
|
body: bytes = b"",
|
|
) -> None:
|
|
self.url = url
|
|
self.status = status
|
|
self.headers = headers or {}
|
|
self._body = body
|
|
|
|
def read(self) -> bytes:
|
|
return self._body
|
|
|
|
def close(self) -> None:
|
|
return None
|
|
|
|
|
|
def load_check_module():
|
|
spec = importlib.util.spec_from_file_location("check_terraform_release_plan", SCRIPT)
|
|
module = importlib.util.module_from_spec(spec)
|
|
assert spec.loader is not None
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def test_download_pinning() -> list[str]:
|
|
module = load_check_module()
|
|
fixture = (FIXTURES / "version-only.json").read_bytes()
|
|
archive_url = "https://archivist.terraform.io/v1/object/example"
|
|
calls: list[str] = []
|
|
|
|
def fake_urlopen(request: Request, **_kwargs):
|
|
url = request.full_url
|
|
calls.append(url)
|
|
host = request.host if hasattr(request, "host") else ""
|
|
if url.startswith("https://app.terraform.io/api/v2/plans/"):
|
|
if request.get_header("Authorization") != "Bearer test-token":
|
|
raise AssertionError("API request is missing the bearer token")
|
|
if "/runs" in url or "/apply" in url or "/discard" in url:
|
|
raise AssertionError(f"download contacted a run-control path: {url}")
|
|
return FakeResponse(
|
|
url=url,
|
|
status=307,
|
|
headers={"Location": archive_url},
|
|
)
|
|
if url == archive_url:
|
|
if request.get_header("Authorization"):
|
|
raise AssertionError("archivist request must not send TF_API_TOKEN")
|
|
return FakeResponse(url=url, status=200, body=fixture)
|
|
raise AssertionError(f"unexpected URL {url} host={host}")
|
|
|
|
plan = module.download_plan_json(PLAN_ID, "test-token", urlopen=fake_urlopen)
|
|
failures: list[str] = []
|
|
if plan["resource_changes"][1]["address"] != (
|
|
"module.environment.aws_elastic_beanstalk_environment.this"
|
|
):
|
|
failures.append("download did not return the version-only fixture")
|
|
if calls != [
|
|
f"https://app.terraform.io/api/v2/plans/{PLAN_ID}/json-output",
|
|
archive_url,
|
|
]:
|
|
failures.append(f"download URLs were {calls}")
|
|
|
|
try:
|
|
module.download_plan_json("run-not-a-plan", "test-token", urlopen=fake_urlopen)
|
|
failures.append("invalid plan id was accepted")
|
|
except ValueError:
|
|
pass
|
|
|
|
def redirect_elsewhere(request: Request, **_kwargs):
|
|
return FakeResponse(
|
|
url=request.full_url,
|
|
status=307,
|
|
headers={"Location": "https://evil.example/plan.json"},
|
|
)
|
|
|
|
try:
|
|
module.download_plan_json(PLAN_ID, "test-token", urlopen=redirect_elsewhere)
|
|
failures.append("redirect to a non-archivist host was accepted")
|
|
except ValueError:
|
|
pass
|
|
|
|
def double_redirect(request: Request, **_kwargs):
|
|
if request.full_url.startswith("https://app.terraform.io/"):
|
|
return FakeResponse(
|
|
url=request.full_url,
|
|
status=307,
|
|
headers={"Location": archive_url},
|
|
)
|
|
return FakeResponse(
|
|
url=request.full_url,
|
|
status=307,
|
|
headers={"Location": "https://archivist.terraform.io/v1/object/other"},
|
|
)
|
|
|
|
try:
|
|
module.download_plan_json(PLAN_ID, "test-token", urlopen=double_redirect)
|
|
failures.append("second archivist redirect was accepted")
|
|
except ValueError:
|
|
pass
|
|
|
|
def not_ready(request: Request, **_kwargs):
|
|
return FakeResponse(url=request.full_url, status=204)
|
|
|
|
try:
|
|
module.download_plan_json(PLAN_ID, "test-token", urlopen=not_ready)
|
|
failures.append("HTTP 204 was polled or accepted")
|
|
except ValueError as exc:
|
|
if "poll" not in str(exc):
|
|
failures.append(f"HTTP 204 error was {exc}")
|
|
|
|
source = SCRIPT.read_text(encoding="utf-8")
|
|
for banned in ("/apply", "/discard", "/runs"):
|
|
if banned in source:
|
|
failures.append(f"download client contains run-control path {banned}")
|
|
|
|
return failures
|
|
|
|
|
|
def _scripted_https_handler(fixture: bytes, archive_url: str):
|
|
calls: list[str] = []
|
|
api_prefix = "https://app.terraform.io/api/v2/plans/"
|
|
|
|
class ScriptedHTTPSHandler(urllib.request.BaseHandler):
|
|
handler_order = 100
|
|
|
|
def https_open(self, req: Request):
|
|
url = req.full_url
|
|
calls.append(url)
|
|
headers = EmailMessage()
|
|
if url.startswith(api_prefix):
|
|
headers["Location"] = archive_url
|
|
body = b""
|
|
status = 307
|
|
msg = "Temporary Redirect"
|
|
elif url == archive_url:
|
|
body = fixture
|
|
status = 200
|
|
msg = "OK"
|
|
else:
|
|
raise AssertionError(f"unexpected URL {url}")
|
|
response = urllib.response.addinfourl(
|
|
io.BytesIO(body),
|
|
headers,
|
|
url,
|
|
code=status,
|
|
)
|
|
response.msg = msg
|
|
return response
|
|
|
|
return ScriptedHTTPSHandler(), calls
|
|
|
|
|
|
def test_download_standard_opener_redirect() -> list[str]:
|
|
"""urllib follows the HCP 307; the guard must still inspect that first hop."""
|
|
module = load_check_module()
|
|
fixture = (FIXTURES / "version-only.json").read_bytes()
|
|
archive_url = "https://archivist.terraform.io/v1/object/example"
|
|
api_url = f"https://app.terraform.io/api/v2/plans/{PLAN_ID}/json-output"
|
|
failures: list[str] = []
|
|
|
|
following_handler, following_calls = _scripted_https_handler(fixture, archive_url)
|
|
followed = urllib.request.build_opener(following_handler).open(api_url)
|
|
try:
|
|
if followed.status != 200:
|
|
failures.append(
|
|
f"standard opener first status was {followed.status}, not 200"
|
|
)
|
|
if following_calls != [api_url, archive_url]:
|
|
failures.append(f"standard opener URLs were {following_calls}")
|
|
finally:
|
|
followed.close()
|
|
|
|
guard_handler, guard_calls = _scripted_https_handler(fixture, archive_url)
|
|
try:
|
|
plan = module.download_plan_json(
|
|
PLAN_ID,
|
|
"test-token",
|
|
handlers=(guard_handler,),
|
|
)
|
|
except ValueError as exc:
|
|
failures.append(f"no-redirect download failed: {exc}")
|
|
return failures
|
|
|
|
if plan["resource_changes"][1]["address"] != (
|
|
"module.environment.aws_elastic_beanstalk_environment.this"
|
|
):
|
|
failures.append("no-redirect download did not return the version-only fixture")
|
|
if guard_calls != [api_url, archive_url]:
|
|
failures.append(f"no-redirect download URLs were {guard_calls}")
|
|
|
|
following_urlopen_handler, _ = _scripted_https_handler(fixture, archive_url)
|
|
following_urlopen = urllib.request.build_opener(following_urlopen_handler).open
|
|
try:
|
|
module.download_plan_json(
|
|
PLAN_ID,
|
|
"test-token",
|
|
urlopen=following_urlopen,
|
|
)
|
|
failures.append("redirect-following urlopen was accepted as the first hop")
|
|
except ValueError as exc:
|
|
if "expected a redirect" not in str(exc):
|
|
failures.append(f"following urlopen error was {exc}")
|
|
|
|
return failures
|
|
|
|
|
|
def main() -> int:
|
|
cases = [
|
|
("version-only", run_case("version-only.json"), 0),
|
|
("wrong-label", run_case("wrong-label.json"), 1),
|
|
("eb-setting-change", run_case("eb-setting-change.json"), 1),
|
|
("nested-unknown-tags", run_case("nested-unknown-tags.json"), 1),
|
|
("unknown-only-description", run_case("unknown-only-description.json"), 1),
|
|
("iam-update", run_case("iam-update.json"), 1),
|
|
("dns-update", run_case("dns-update.json"), 1),
|
|
("create", run_case("create.json"), 1),
|
|
("delete", run_case("delete.json"), 1),
|
|
("replace", run_case("replace.json"), 1),
|
|
("multiple-updates", run_case("multiple-updates.json"), 1),
|
|
("empty", run_case("empty.json"), 1),
|
|
]
|
|
failures = [
|
|
(name, result, expected)
|
|
for name, result, expected in cases
|
|
if result.returncode != expected
|
|
]
|
|
download_failures = test_download_pinning()
|
|
redirect_failures = test_download_standard_opener_redirect()
|
|
download_failures.extend(redirect_failures)
|
|
if failures or download_failures:
|
|
if failures:
|
|
print(
|
|
"FAIL: release plan-check cases failed: "
|
|
+ ", ".join(name for name, _, _ in failures),
|
|
file=sys.stderr,
|
|
)
|
|
for name, result, expected in failures:
|
|
print(
|
|
f"{name}: expected {expected}, got {result.returncode}\n"
|
|
f"{result.stdout}{result.stderr}",
|
|
file=sys.stderr,
|
|
)
|
|
for item in download_failures:
|
|
print(f"FAIL: {item}", file=sys.stderr)
|
|
return 1
|
|
print("PASS: Terraform release plan safety checks")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|