mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-10-06 03:02:03 +00:00
The contract tests still asserted the v1.0.19 SHA after the workflow pin bump, so CI failed on the PyJWT bump PR.
226 lines
8.7 KiB
Python
226 lines
8.7 KiB
Python
"""Contracts for the HCP Terraform seam (PLAT-74 / PLAT-216)."""
|
|
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
TERRAFORM = ROOT / "terraform"
|
|
HCP_IAM = (TERRAFORM / "hcp_iam.tf").read_text()
|
|
CI = (ROOT / ".github" / "workflows" / "ci.yaml").read_text()
|
|
LOCALS = (TERRAFORM / "locals.tf").read_text()
|
|
VARIABLES = (TERRAFORM / "variables.tf").read_text()
|
|
|
|
|
|
def _tf_without_comments(text: str) -> str:
|
|
return "\n".join(line.split("#", 1)[0] for line in text.splitlines())
|
|
|
|
|
|
def test_sam_template_removed():
|
|
assert not (ROOT / "template.yaml").exists()
|
|
assert not (ROOT / "samconfig.toml.example").exists()
|
|
|
|
|
|
def test_zip_cd_removed():
|
|
assert not (ROOT / ".github" / "workflows" / "deploy.yaml").exists()
|
|
for path in TERRAFORM.glob("*.tf"):
|
|
assert 'resource "aws_lambda_function"' not in path.read_text()
|
|
assert not (TERRAFORM / "apigateway.tf").exists()
|
|
assert not (TERRAFORM / "events.tf").exists()
|
|
|
|
|
|
def test_schedules_disabled_by_default():
|
|
chunk = (
|
|
(TERRAFORM / "variables.tf")
|
|
.read_text()
|
|
.split('variable "schedules_enabled"')[1]
|
|
)
|
|
chunk = chunk.split("variable ")[0]
|
|
assert "default = false" in chunk or "default = false" in chunk
|
|
|
|
|
|
def test_ecs_schedules_disabled_by_default():
|
|
chunk = (
|
|
(TERRAFORM / "variables.tf")
|
|
.read_text()
|
|
.split('variable "ecs_schedules_enabled"')[1]
|
|
)
|
|
chunk = chunk.split("variable ")[0]
|
|
assert "default = false" in chunk or "default = false" in chunk
|
|
|
|
|
|
def test_workspaces_use_app_tag():
|
|
versions = (TERRAFORM / "versions.tf").read_text()
|
|
assert 'tags = ["app:afterhours-shift-manager"]' in versions
|
|
assert 'name = "afterhours-shift-manager-prod"' not in versions
|
|
assert 'hcp_workspace = "${local.project}-${var.environment}"' in LOCALS
|
|
assert "seahaven-${var.environment}" in LOCALS
|
|
|
|
|
|
def test_ecs_ignore_changes_and_task_size():
|
|
ecs = (TERRAFORM / "ecs.tf").read_text()
|
|
assert "ignore_changes = [container_definitions]" in ecs
|
|
assert "ignore_changes = [task_definition, desired_count]" in ecs
|
|
assert 'cpu = "512"' in ecs
|
|
assert 'memory = "1024"' in ecs
|
|
assert 'cpu_architecture = "ARM64"' in ecs
|
|
assert 'path = "/api/health"' in ecs
|
|
|
|
|
|
def test_stack_owns_a_vpc_instead_of_looking_up_default():
|
|
vpc = (TERRAFORM / "vpc.tf").read_text()
|
|
ecs = (TERRAFORM / "ecs.tf").read_text()
|
|
assert 'resource "aws_vpc" "this"' in vpc
|
|
assert "cidr_block = local.vpc_cidr" in vpc
|
|
assert 'vpc_cidr = "10.70.0.0/16"' in LOCALS
|
|
assert 'data "aws_vpc" "default"' not in ecs
|
|
assert "data.aws_vpc.default" not in ecs
|
|
assert "data.aws_subnets.default" not in ecs
|
|
assert "aws_vpc.this.id" in ecs
|
|
assert "aws_subnet.public[*].id" in ecs
|
|
assert "ec2:CreateVpc" in HCP_IAM
|
|
assert 'sid = "RefreshVpc"' in HCP_IAM
|
|
assert "afterhours-shift-manager-ecs" in HCP_IAM
|
|
assert "hcptf_apply_ecs" in HCP_IAM
|
|
assert 'resource "aws_iam_policy" "hcptf_apply_ecs"' in HCP_IAM
|
|
assert 'resource "aws_iam_role_policy" "hcptf_apply_ecs"' not in HCP_IAM
|
|
assert "aws_iam_policy.hcptf_apply_ecs.arn" in HCP_IAM
|
|
assert 'sid = "CreateElbAndEcsServiceLinkedRoles"' in HCP_IAM
|
|
assert "iam:CreateServiceLinkedRole" in HCP_IAM
|
|
|
|
|
|
def test_ecs_task_boundary_uses_static_arns():
|
|
iam = (TERRAFORM / "iam.tf").read_text()
|
|
chunk = iam.split('data "aws_iam_policy_document" "ecs_task_boundary"')[1]
|
|
chunk = chunk.split("resource ")[0]
|
|
assert "aws_dynamodb_table.shifts" not in chunk
|
|
assert "aws_sqs_queue.jobs" not in chunk
|
|
assert "aws_ecr_repository.api" not in chunk
|
|
assert "aws_cloudwatch_log_group.api" not in chunk
|
|
assert "table/${local.table_name}" in chunk
|
|
assert "log-group:/ecs/${local.project}" in chunk
|
|
|
|
|
|
def test_deploy_api_workflow_exists():
|
|
deploy_api = (ROOT / ".github" / "workflows" / "deploy-api.yaml").read_text()
|
|
pin = "cd-hcp-fargate.yaml@47185fa602dffddb8297db5f3525d7c9bc05d7cd # v1.0.21"
|
|
assert deploy_api.count(pin) == 2
|
|
assert "ssm-prefix: /afterhours-shift-manager/deploy" in deploy_api
|
|
assert "docker-platform: linux/arm64" in deploy_api
|
|
assert "ship-gate: true" in deploy_api
|
|
assert "gh release create" in deploy_api
|
|
assert "needs.target.outputs.environment" not in deploy_api
|
|
|
|
|
|
def test_in_repo_hcptf_roles():
|
|
assert 'apply_role = "hcptf-afterhours-shift-manager"' in LOCALS
|
|
assert 'plan_role = "hcptf-afterhours-shift-manager-plan"' in LOCALS
|
|
assert "hcptf_apply" in HCP_IAM
|
|
assert "DenyCreatePolicy" in HCP_IAM
|
|
|
|
|
|
def test_ci_runs_pytest_and_terraform_validate():
|
|
assert "ci-python-sam" not in CI
|
|
assert "ci-python-app.yaml@47185fa602dffddb8297db5f3525d7c9bc05d7cd # v1.0.21" in CI
|
|
assert "ci-terraform.yaml@47185fa602dffddb8297db5f3525d7c9bc05d7cd # v1.0.21" in CI
|
|
assert "ci-autofix.yaml@47185fa602dffddb8297db5f3525d7c9bc05d7cd # v1.0.21" in CI
|
|
assert "name: ci-complete" in CI
|
|
assert "pytest" in CI
|
|
assert "terraform fmt -check" not in CI
|
|
assert "openapi:lint" in CI
|
|
assert "npm ci" in CI
|
|
|
|
|
|
def test_openapi_uses_redocly_recommended():
|
|
redocly = (ROOT / ".redocly.yaml").read_text()
|
|
package = (ROOT / "package.json").read_text()
|
|
spec = (ROOT / "openapi.yaml").read_text()
|
|
assert "extends:" in redocly
|
|
assert "- recommended" in redocly
|
|
assert "operation-2xx-response: off" in redocly
|
|
assert "operation-4xx-response: error" in redocly
|
|
assert "rule/operation-2xx-or-3xx-response" in redocly
|
|
assert "severity: error" in redocly
|
|
assert "optionsShifts" not in spec
|
|
health = spec.split("/api/health:", 1)[1].split("\n /", 1)[0]
|
|
assert '"403":' in health
|
|
assert '"400":' not in health
|
|
assert "root: openapi.yaml" in redocly
|
|
assert '"openapi:lint"' in package
|
|
assert '"@redocly/cli":' in package
|
|
assert "openapi: 3.1.0" in spec
|
|
assert "required: [stage, sha]" in spec
|
|
|
|
|
|
def test_checkcomponents_queue_arn_variable_matches_iam_references():
|
|
assert 'variable "checkcomponents_queue_arn"' in VARIABLES
|
|
iam = (TERRAFORM / "iam.tf").read_text()
|
|
assert "var.checkcomponents_queue_arn" in iam
|
|
boundary = (TERRAFORM / "lambda_boundary.tf").read_text()
|
|
assert "var.checkcomponents_queue_arn" in boundary
|
|
data_tf = (TERRAFORM / "data.tf").read_text()
|
|
assert "dev_has_no_paychex" in data_tf
|
|
assert "checkcomponents_pair" in data_tf
|
|
|
|
|
|
def test_leftover_lambda_iam_roles_removed():
|
|
for path in TERRAFORM.glob("*.tf"):
|
|
body = _tf_without_comments(path.read_text())
|
|
assert 'resource "aws_iam_role" "lambda"' not in body
|
|
assert 'resource "aws_iam_role_policy" "lambda"' not in body
|
|
assert 'resource "aws_iam_role_policy_attachment" "lambda_basic"' not in body
|
|
assert 'data "aws_iam_policy_document" "lambda_assume"' not in body
|
|
|
|
|
|
def test_lambda_boundary_policy_remains():
|
|
boundary = (TERRAFORM / "lambda_boundary.tf").read_text()
|
|
assert 'resource "aws_iam_policy" "lambda_boundary"' in boundary
|
|
assert "afterhours-shift-manager-lambda-boundary" in boundary
|
|
|
|
|
|
def test_local_functions_still_lists_packaging_keys():
|
|
for name in (
|
|
"afterhours-shift-manager",
|
|
"afterhours-weekly-post",
|
|
"afterhours-roster-sync",
|
|
"afterhours-roster-api",
|
|
"afterhours-ring-scheduler",
|
|
"afterhours-holiday-router",
|
|
"afterhours-portal-api",
|
|
):
|
|
assert name in LOCALS
|
|
assert "afterhours-release-notifier" not in LOCALS
|
|
assert "weekly_post" in LOCALS
|
|
|
|
|
|
def test_github_deploy_trust_covers_image_only():
|
|
iam = (TERRAFORM / "iam_github_deploy.tf").read_text()
|
|
assert "environment:prod" in iam or "environment:prod" in LOCALS
|
|
assert "environment:dev" in iam or "environment:dev" in LOCALS
|
|
assert "deploy.yaml@" not in iam
|
|
assert "deploy-api.yaml@" not in iam
|
|
assert "Sea-Haven-Industries/.github/.github/workflows/cd-hcp-fargate.yaml@*" in iam
|
|
assert "ecs:ListTasks" in iam
|
|
|
|
|
|
def test_plan_refresh_includes_provider6_s3_gets():
|
|
assert "s3:GetLifecycleConfiguration" in HCP_IAM
|
|
assert "s3:GetReplicationConfiguration" in HCP_IAM
|
|
assert "s3:GetBucketReplication" in HCP_IAM
|
|
|
|
|
|
def test_origins_use_fargate_url():
|
|
outputs = (TERRAFORM / "outputs.tf").read_text()
|
|
assert "aws_apigatewayv2_api.http" not in outputs
|
|
assert "${local.api_url}/slack/events" in outputs
|
|
assert "value = local.api_url" in outputs
|
|
assert 'output "vpc_id"' in outputs
|
|
assert 'output "public_subnet_ids"' in outputs
|
|
assert "aws_vpc.this.id" in outputs
|
|
|
|
|
|
def test_alb_alarms_remain():
|
|
alarms = (TERRAFORM / "alarms.tf").read_text()
|
|
assert "ALB-5xx-" in alarms
|
|
assert "ALB-Latency-" in alarms
|
|
assert "ALB-UnhealthyHost-" in alarms
|
|
assert "ApiGateway-" not in alarms
|
|
assert "Lambda-" not in alarms
|