diff --git a/lambdas/po/email_processor/handler.py b/lambdas/po/email_processor/handler.py index 9c5b620..6063c65 100644 --- a/lambdas/po/email_processor/handler.py +++ b/lambdas/po/email_processor/handler.py @@ -211,14 +211,21 @@ The Coupa commodity/category field if present in the email (e.g., "Maintenance - def get_anthropic_client() -> anthropic.Anthropic: - """Create Anthropic client, fetching API key from Secrets Manager.""" - if ANTHROPIC_API_KEY_SECRET_ARN: - secrets = boto3.client("secretsmanager") - secret = secrets.get_secret_value(SecretId=ANTHROPIC_API_KEY_SECRET_ARN) - api_key = secret["SecretString"] - return anthropic.Anthropic(api_key=api_key) - # Fall back to ANTHROPIC_API_KEY env var (for local testing) - return anthropic.Anthropic() + """Create Anthropic client, fetching API key from Secrets Manager. + + Requires ANTHROPIC_API_KEY_SECRET_ARN to be set. The previous silent + fallback to a plaintext ANTHROPIC_API_KEY env var is removed: a misconfigured + deploy must fail loudly rather than quietly run on an unmanaged key. + """ + if not ANTHROPIC_API_KEY_SECRET_ARN: + raise RuntimeError( + "ANTHROPIC_API_KEY_SECRET_ARN is not set; refusing to fall back to a " + "plaintext API key. Configure the Secrets Manager ARN." + ) + secrets = boto3.client("secretsmanager") + secret = secrets.get_secret_value(SecretId=ANTHROPIC_API_KEY_SECRET_ARN) + api_key = secret["SecretString"] + return anthropic.Anthropic(api_key=api_key) def parse_raw_email(raw_bytes: bytes) -> dict: diff --git a/lambdas/wo/email_processor/handler.py b/lambdas/wo/email_processor/handler.py index 2abdc8f..f51cc5e 100644 --- a/lambdas/wo/email_processor/handler.py +++ b/lambdas/wo/email_processor/handler.py @@ -66,14 +66,21 @@ Rules: def get_anthropic_client() -> anthropic.Anthropic: - """Create Anthropic client, fetching API key from Secrets Manager if configured.""" - if ANTHROPIC_API_KEY_SECRET_ARN: - secrets = boto3.client("secretsmanager") - secret = secrets.get_secret_value(SecretId=ANTHROPIC_API_KEY_SECRET_ARN) - api_key = secret["SecretString"] - return anthropic.Anthropic(api_key=api_key) - # Fall back to ANTHROPIC_API_KEY env var (for local testing) - return anthropic.Anthropic() + """Create Anthropic client, fetching API key from Secrets Manager. + + Requires ANTHROPIC_API_KEY_SECRET_ARN to be set. The previous silent + fallback to a plaintext ANTHROPIC_API_KEY env var is removed: a misconfigured + deploy must fail loudly rather than quietly run on an unmanaged key. + """ + if not ANTHROPIC_API_KEY_SECRET_ARN: + raise RuntimeError( + "ANTHROPIC_API_KEY_SECRET_ARN is not set; refusing to fall back to a " + "plaintext API key. Configure the Secrets Manager ARN." + ) + secrets = boto3.client("secretsmanager") + secret = secrets.get_secret_value(SecretId=ANTHROPIC_API_KEY_SECRET_ARN) + api_key = secret["SecretString"] + return anthropic.Anthropic(api_key=api_key) def parse_raw_email(raw_bytes: bytes) -> dict: