"""nova apply — resolve a contract + synthesize local env (REQ-330, REQ-332). Subcommand (≤50 lines, ≤3 functions, delegates to core/ — NFR-7). nova apply --local --contract .nova/contract.yml [--sign-local-review] nova apply --contract contracts/microservice.yml --out stack.json --local: calls core.env.synthesize_local_env() + core.contract_resolver.resolve() --sign-local-review: calls core.jws_attestation.sign_attestation() (REQ-332) """ from __future__ import annotations import json from core import env from core.contract_resolver import resolve from core.jws_attestation import sign_attestation def add_parser(subparsers): p = subparsers.add_parser("apply", help="resolve a contract (+ local env synth)") p.add_argument("--contract", default=".nova/contract.yml", help="contract YAML path") p.add_argument("--out", default=None, help="output path (default: stdout)") p.add_argument("--local", action="store_true", help="synthesize a local env (no AWS)") p.add_argument("--environment", default=None, help="environment override") p.add_argument("--sign-local-review", action="store_true", help="sign a local-review attestation (REQ-332)") p.add_argument("--pat", default=None, help="PAT for --sign-local-review") p.set_defaults(_run=run) def run(args) -> int: synth = env.synthesize_local_env(args.contract, environment=args.environment) if args.local else None env_override = (synth["name"] if isinstance(synth, dict) else None) or args.environment result = resolve(args.contract, environment_override=env_override) blob = json.dumps(result, indent=2) + "\n" pat = args.pat or env.get_env("PAT", "") or "" attestation = sign_attestation({"contract": args.contract, "review": "local"}, pat) if (args.sign_local_review and pat) else None blob = blob + (attestation + "\n" if attestation else "") print(blob) if args.out is None else open(args.out, "w").write(blob) return 0 if __name__ == "__main__": import sys print("use: nova apply --contract [--local] [--sign-local-review]", file=sys.stderr)