mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-01 09:53:15 +00:00
Add import-only dev and staging state with least-privilege HCP authentication and plan safety guards.
74 lines
2.1 KiB
Python
74 lines
2.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Reject unsafe actions in a live Terraform import plan."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
ALLOWED_MANAGED_TYPES = {"aws_iam_role", "aws_iam_role_policy"}
|
|
UNSAFE_ACTIONS = {"create", "delete"}
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("plan_json", type=Path)
|
|
parser.add_argument(
|
|
"--allow-update",
|
|
action="store_true",
|
|
help="Allow in-place updates after the initial no-op import is proven.",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
plan = json.loads(args.plan_json.read_text(encoding="utf-8"))
|
|
violations: list[str] = []
|
|
managed = 0
|
|
updates = 0
|
|
|
|
for resource in plan.get("resource_changes", []):
|
|
if resource.get("mode", "managed") != "managed":
|
|
continue
|
|
|
|
resource_type = resource.get("type", "")
|
|
address = resource.get("address", "<unknown>")
|
|
actions = set(resource.get("change", {}).get("actions", []))
|
|
managed += 1
|
|
|
|
if resource_type not in ALLOWED_MANAGED_TYPES:
|
|
violations.append(
|
|
f"{address}: managed type {resource_type!r} is outside the live ownership boundary"
|
|
)
|
|
|
|
unsafe = sorted(actions & UNSAFE_ACTIONS)
|
|
if unsafe:
|
|
violations.append(f"{address}: unsafe actions {unsafe}")
|
|
|
|
if "update" in actions:
|
|
updates += 1
|
|
if not args.allow_update:
|
|
violations.append(
|
|
f"{address}: update is forbidden during the initial no-op import"
|
|
)
|
|
|
|
if violations:
|
|
print("FAIL: live Terraform plan is not import-safe", file=sys.stderr)
|
|
for violation in violations:
|
|
print(f" - {violation}", file=sys.stderr)
|
|
return 1
|
|
|
|
mode = "controlled update" if args.allow_update else "no-op import"
|
|
print(
|
|
f"PASS: {mode} plan has {managed} managed resources, "
|
|
f"{updates} updates, and no create/delete/replace actions"
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|