#!/usr/bin/env python3 """Environment onboarding check. Reads a contract's `environment` field and looks up the matching `core/environments/.json`. If no matching file exists, prints a friendly onboarding prompt and exits non-zero, halting the pipeline before any work is done. Usage: python3 core/environment_check.py python3 core/environment_check.py --env dev """ import sys from pathlib import Path try: import yaml except ImportError: sys.stderr.write("PyYAML is required (pip install pyyaml)\n") sys.exit(2) def _environments_dir(root=None): if root is None: root = Path(__file__).resolve().parent.parent return Path(root) / "core" / "environments" def _contract_environment(contract_path): with open(contract_path) as f: contract = yaml.safe_load(f) return contract.get("environment") def _onboarding_message(env_name): return ( "=== ACDL Environment Onboarding ===\n" f"No environment named '{env_name}' is bound to this repository.\n\n" "ACDL environments are platform-managed. The platform provisions on\n" "your behalf:\n" " - an AWS account (or a scoped partition of one)\n" " - a network (VPC + subnets)\n" " - a state backend (an S3 bucket + DynamoDB lock table)\n" " - an IAM role surfaced to your repo via attribute-based\n" " authorization (ABAC)\n\n" "You do not provide an AWS account, VPC, subnet, or state bucket.\n\n" "To request an environment:\n" " 1. Contact the platform team with your repo name + the\n" " environment name you need (e.g. 'dev').\n" " 2. The platform team provisions the account/network/state/role\n" " and binds the environment to your repo.\n" " 3. Your next pipeline run will proceed normally.\n\n" "Expected turnaround: contact the platform team for current SLA.\n" "===================================\n" ) def check(contract_path=None, env_name=None, root=None): """Return (ok: bool, message: str). If env_name is None it is read from the contract at contract_path. ok is True when an environment definition exists; False otherwise. On False, message is the friendly onboarding prompt. """ if env_name is None: if contract_path is None: return (False, "no contract or environment name supplied") env_name = _contract_environment(contract_path) if env_name is None: return (False, "contract has no 'environment' field") env_file = _environments_dir(root) / f"{env_name}.json" if env_file.is_file(): return (True, f"environment '{env_name}' is bound ({env_file})") return (False, _onboarding_message(env_name)) def main(argv): contract_path = None env_name = None for arg in argv[1:]: if arg.startswith("--env="): env_name = arg.split("=", 1)[1] elif arg.startswith("--"): sys.stderr.write(f"unknown flag: {arg}\n") return 2 else: contract_path = arg ok, message = check(contract_path=contract_path, env_name=env_name) if ok: print(message) return 0 sys.stdout.write(message) return 1 if __name__ == "__main__": sys.exit(main(sys.argv))