"""REQ-104: environment JSON schema + qa/prod/dr bindings + load().""" import json import sys from pathlib import Path import jsonschema import pytest ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT)) from core.environment_check import load, check ENV_DIR = ROOT / "core" / "environments" SCHEMA = ROOT / "schemas" / "environment.schema.json" ENV_FILES = ["dev.json", "qa.json", "prod.json", "dr.json"] def _schema(): return json.loads(SCHEMA.read_text()) @pytest.mark.parametrize("env_file", ENV_FILES) def test_env_file_validates_against_schema(env_file): env = json.loads((ENV_DIR / env_file).read_text()) jsonschema.validate(env, _schema()) def test_dev_env_has_expected_fields(): env = load("dev") assert env["name"] == "dev" # P03 W3 (REQ-319, D-203): dev is bound to the real account. assert env["account_id"] == "581513795199" assert env["region"] == "us-east-1" assert env["autonomy"] == "full" assert env["confidence_threshold"] == 0.50 assert "state_backend" in env assert "bucket" in env["state_backend"] assert env["state_backend"]["bucket"] == "nova-tfstate-581513795199-us-east-1" assert "network" in env def test_qa_env_attested_with_075_threshold(): env = load("qa") assert env["autonomy"] == "attested" assert env["confidence_threshold"] == 0.75 def test_prod_env_attested_with_090_threshold(): env = load("prod") assert env["autonomy"] == "attested" assert env["confidence_threshold"] == 0.90 def test_dr_env_attested_with_095_threshold(): env = load("dr") assert env["autonomy"] == "attested" assert env["confidence_threshold"] == 0.95 def test_load_unknown_env_raises(): with pytest.raises(FileNotFoundError): load("nonexistent") def test_load_returns_dict(): env = load("dev") assert isinstance(env, dict) def test_placeholder_account_warning_for_non_dev(capsys): """A stderr warning is emitted when account_id is the placeholder and env != dev.""" load("qa") captured = capsys.readouterr() assert "placeholder account_id" in captured.err assert "qa" in captured.err def test_no_warning_for_dev_placeholder(capsys): load("dev") captured = capsys.readouterr() assert "placeholder account_id" not in captured.err def test_check_still_works_for_dev(): ok, msg = check(env_name="dev") assert ok is True def test_check_fails_for_unknown_env(): ok, msg = check(env_name="nonexistent") assert ok is False assert "nonexistent" in msg def test_account_id_is_12_digits(): for env_file in ENV_FILES: env = json.loads((ENV_DIR / env_file).read_text()) assert len(env["account_id"]) == 12 assert env["account_id"].isdigit() def test_v14_schema_rejects_undocumented_fields(): """v1.14 (REQ-145): additionalProperties: false rejects unknown fields.""" schema = json.loads(SCHEMA.read_text()) bad_env = { "name": "dev", "account_id": "123456789012", "region": "us-east-1", "state_backend": {"bucket": "test", "lock_table": "test"}, "network": {"vpc_cidr": "10.0.0.0/16", "azs": ["us-east-1a"]}, "runner_role_arn": "arn:aws:iam::123456789012:role/test", "autonomy": "full", "confidence_threshold": 0.5, "rogue_field": "should be rejected" } with pytest.raises(jsonschema.ValidationError, match="Additional properties are not allowed"): jsonschema.validate(bad_env, schema) def test_v14_schema_validates_bucket_name_format(): """v1.14 (REQ-145): state_backend.bucket must match S3 naming rules.""" schema = json.loads(SCHEMA.read_text()) bad_env = { "name": "dev", "account_id": "123456789012", "region": "us-east-1", "state_backend": {"bucket": "Invalid_Bucket!", "lock_table": "test"}, "network": {"vpc_cidr": "10.0.0.0/16", "azs": ["us-east-1a"]}, "runner_role_arn": "arn:aws:iam::123456789012:role/test", "autonomy": "full", "confidence_threshold": 0.5 } with pytest.raises(jsonschema.ValidationError, match="does not match"): jsonschema.validate(bad_env, schema) def test_v14_schema_validates_arn_format(): """v1.14 (REQ-145): runner_role_arn must match ARN format.""" schema = json.loads(SCHEMA.read_text()) bad_env = { "name": "dev", "account_id": "123456789012", "region": "us-east-1", "state_backend": {"bucket": "test", "lock_table": "test"}, "network": {"vpc_cidr": "10.0.0.0/16", "azs": ["us-east-1a"]}, "runner_role_arn": "not-an-arn", "autonomy": "full", "confidence_threshold": 0.5 } with pytest.raises(jsonschema.ValidationError, match="does not match"): jsonschema.validate(bad_env, schema) def test_v14_schema_validates_cidr_format(): """v1.14 (REQ-145): vpc_cidr must match CIDR format.""" schema = json.loads(SCHEMA.read_text()) bad_env = { "name": "dev", "account_id": "123456789012", "region": "us-east-1", "state_backend": {"bucket": "test", "lock_table": "test"}, "network": {"vpc_cidr": "not-a-cidr", "azs": ["us-east-1a"]}, "runner_role_arn": "arn:aws:iam::123456789012:role/test", "autonomy": "full", "confidence_threshold": 0.5 } with pytest.raises(jsonschema.ValidationError, match="does not match"): jsonschema.validate(bad_env, schema)