"""Nova IdP JWKS endpoint Lambda (REQ-338, D-230). Serves the KMS public key as a JWK in a standard JWKS response. The endpoint is a Lambda function URL with ``AuthType: NONE`` (JWKS is public-key only — configured in CloudFormation, not in code). Response: * ``Content-Type: application/json`` * ``Cache-Control: public, max-age=3600`` (1h — clients cache the JWKS) * ``Access-Control-Allow-Origin: *`` (JWKS is public) * ``body: {"keys": []}`` The JWK is built via :func:`core.kms_signing.get_jwk` from the KMS public key (DER SPKI → ``cryptography`` → JWK). Dual-use (REQ-329): ``__main__`` CLI block for local testing (``--print-jwks``). """ from __future__ import annotations import json import os import sys OIDC_KMS_KEY_ID = os.environ.get("NOVA_OIDC_KMS_KEY_ID", "alias/nova-oidc-signing") def lambda_handler(event, context): """AWS Lambda handler — serve the JWKS response (REQ-338).""" try: from core.kms_signing import get_jwk jwk = get_jwk(key_id=OIDC_KMS_KEY_ID) return { "statusCode": 200, "headers": { "Content-Type": "application/json", "Cache-Control": "public, max-age=3600", "Access-Control-Allow-Origin": "*", }, "body": json.dumps({"keys": [jwk]}), } except Exception as e: return { "statusCode": 500, "headers": {"Content-Type": "application/json"}, "body": json.dumps({"error": str(e)}), } def cli_main(argv=None): """CLI entry point (REQ-329 dual-use). ``--print-jwks`` → stdout.""" raw = argv if argv is not None else sys.argv[1:] if "--print-jwks" in raw: resp = lambda_handler({}, None) sys.stdout.write(resp["body"] + "\n") return resp.get("statusCode", 200) - 200 print("Usage: python3 -m core.lambda.nova_idp_jwks --print-jwks", file=sys.stderr) return 2 if __name__ == "__main__": # pragma: no cover - CLI entry sys.exit(cli_main())