0d2cbdb423
Genericize forge-detection code: gitea→forge/generic_forge, GITEA_ACTOR→FORGE_ACTOR. Drop .gitea byte-identity test assertions (keep GitHub-side + contract conformance). Add test_no_forge_mentions.py guard test (REQ-230). Delete completed migration docs (NOVA_MIGRATION.md, NOVA_AWS_MIGRATION.md). Move NO_HUMANS_THESIS.md to .ciagent/ (internal artifact). Strip ciagent-internal provenance from synced docs (REQ-/D-/P-/CAP- IDs, milestone headers, .ciagent/PROJECT.md citations). Trim README.md (reusable deploy section, local key rotation paragraph). Fix version-tag drift (@v1.13→@v1.19, acdl/→nova/). ---ci--- project: acdl phase: 1 milestone: v1.20 status: execute requirements: [REQ-230, REQ-231, REQ-232] ---/ci---
102 lines
4.3 KiB
Python
102 lines
4.3 KiB
Python
"""Tests for the decommission transform (REQ-92) + decommission pipeline mode."""
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
import yaml
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
class TestDecommissionTransform:
|
|
"""REQ-92: decommission_transform zeroes counts + disables deletion protection."""
|
|
|
|
def test_decommission_transform_zeros_desired_count(self):
|
|
from core.contract_resolver import decommission_transform
|
|
stack = {
|
|
"version": "1.0.0",
|
|
"stack": {"name": "test", "kind": "l1", "depth": 1},
|
|
"resources": [
|
|
{"id": "svc", "type": "aws:ecs:service", "module": "ecs-service@1.0.0",
|
|
"inputs": {"desired_count": 3}, "outputs": {}, "nfrs": {"deletion_protection": True}},
|
|
],
|
|
}
|
|
result = decommission_transform(stack)
|
|
assert result["resources"][0]["inputs"]["desired_count"] == 0
|
|
assert result["resources"][0]["nfrs"]["deletion_protection"] is False
|
|
|
|
def test_decommission_transform_zeros_min_max_capacity(self):
|
|
from core.contract_resolver import decommission_transform
|
|
stack = {
|
|
"version": "1.0.0",
|
|
"stack": {"name": "test", "kind": "l1", "depth": 1},
|
|
"resources": [
|
|
{"id": "asg", "type": "aws:autoscaling:group", "module": "asg@1.0.0",
|
|
"inputs": {"min_capacity": 2, "max_capacity": 10}, "outputs": {}, "nfrs": {}},
|
|
],
|
|
}
|
|
result = decommission_transform(stack)
|
|
assert result["resources"][0]["inputs"]["min_capacity"] == 0
|
|
assert result["resources"][0]["inputs"]["max_capacity"] == 0
|
|
assert result["resources"][0]["nfrs"]["deletion_protection"] is False
|
|
|
|
def test_decommission_transform_sets_deletion_protection_false_on_all(self):
|
|
from core.contract_resolver import decommission_transform
|
|
stack = {
|
|
"version": "1.0.0",
|
|
"stack": {"name": "test", "kind": "l2", "depth": 1},
|
|
"resources": [
|
|
{"id": "s3", "type": "aws:s3:bucket", "module": "s3@1.0.0",
|
|
"inputs": {}, "outputs": {}, "nfrs": {"deletion_protection": True}},
|
|
{"id": "rds", "type": "aws:rds:instance", "module": "rds@1.0.0",
|
|
"inputs": {}, "outputs": {}, "nfrs": {"deletion_protection": True}},
|
|
],
|
|
}
|
|
result = decommission_transform(stack)
|
|
for res in result["resources"]:
|
|
assert res["nfrs"]["deletion_protection"] is False
|
|
|
|
def test_decommission_transform_handles_empty_nfrs(self):
|
|
from core.contract_resolver import decommission_transform
|
|
stack = {
|
|
"version": "1.0.0",
|
|
"stack": {"name": "test", "kind": "l1", "depth": 1},
|
|
"resources": [
|
|
{"id": "s3", "type": "aws:s3:bucket", "module": "s3@1.0.0",
|
|
"inputs": {}, "outputs": {}},
|
|
],
|
|
}
|
|
result = decommission_transform(stack)
|
|
assert result["resources"][0]["nfrs"]["deletion_protection"] is False
|
|
|
|
|
|
class TestDecommissionPipelineContract:
|
|
"""REQ-92: decommission mode in the deploy pipeline contract + workflows."""
|
|
|
|
def test_deploy_workflow_has_decommission_mode(self):
|
|
wf = yaml.safe_load(open(ROOT / ".github/workflows/deploy.yml"))
|
|
on_key = "on" if "on" in wf else True
|
|
inputs = wf[on_key]["workflow_call"]["inputs"]
|
|
assert "mode" in inputs
|
|
assert "decommission" in inputs["mode"]["description"]
|
|
|
|
def test_deploy_workflow_has_change_request_id_input(self):
|
|
wf = yaml.safe_load(open(ROOT / ".github/workflows/deploy.yml"))
|
|
on_key = "on" if "on" in wf else True
|
|
inputs = wf[on_key]["workflow_call"]["inputs"]
|
|
assert "changeRequestId" in inputs
|
|
|
|
def test_deploy_workflow_decommission_requires_change_request_id(self):
|
|
wf_text = open(ROOT / ".github/workflows/deploy.yml").read()
|
|
assert "changeRequestId" in wf_text
|
|
assert "decommission" in wf_text
|
|
|
|
def test_consumer_guide_has_decommission_section(self):
|
|
guide = open(ROOT / "docs/consumer-guide.md").read()
|
|
assert "Decommissioning a stack" in guide
|
|
assert "decommission-gate-sre" in guide
|
|
assert "decommission-destroy-sre" in guide |