Source code for swxsoc_reach.net.auth

"""UDL authentication helpers.

Resolves the UDL HTTP Basic auth credential used by
:func:`swxsoc_reach.net.udl.download_UDL_reach_window` (and the legacy
relative-time wrapper). Two sources are supported, in priority order:

1. The ``BASICAUTH`` environment variable (local-dev fallback / what an
   operator pre-exports).
2. AWS Secrets Manager via ``SECRET_ARN_UDL`` — the secret's
   ``SecretString`` is parsed as JSON and the ``basicauth`` field is
   used. This matches the existing scheduled-Lambda pattern.

``boto3`` is imported lazily inside :func:`resolve_udl_auth` so this
module remains importable on environments where ``boto3`` is not
installed (e.g. running the package without the ``net`` extra and
relying on a pre-set ``BASICAUTH``).
"""

from __future__ import annotations

import json
import os

from swxsoc_reach import log

_BASICAUTH_ENV = "BASICAUTH"
_SECRET_ARN_ENV = "SECRET_ARN_UDL"
_SECRET_KEY = "basicauth"


[docs] def resolve_udl_auth(region_name: str | None = None) -> str: """Resolve the UDL HTTP Basic auth credential. Resolution order: 1. If ``BASICAUTH`` is set in the environment, return it directly and do not touch AWS. 2. Else if ``SECRET_ARN_UDL`` is set, fetch the secret from AWS Secrets Manager, parse its ``SecretString`` as JSON, extract the ``basicauth`` field, write it back to ``os.environ['BASICAUTH']`` (so downstream code that reads the env var continues to work unchanged), and return it. 3. Else raise :class:`RuntimeError`. Parameters ---------- region_name : str or None, optional Optional AWS region passed to ``boto3.session.Session``. When ``None``, ``boto3``'s standard region resolution chain is used (``AWS_REGION`` / ``AWS_DEFAULT_REGION`` / config file). Returns ------- str The UDL HTTP Basic auth credential value. Raises ------ RuntimeError If neither ``BASICAUTH`` nor ``SECRET_ARN_UDL`` is set, if the ``boto3`` package is not installed when Secrets Manager resolution is attempted, or if the secret payload does not contain a ``basicauth`` key. """ pre_set = os.environ.get(_BASICAUTH_ENV) if pre_set: log.info("Using UDL credential from BASICAUTH environment variable") return pre_set secret_arn = os.environ.get(_SECRET_ARN_ENV) if not secret_arn: raise RuntimeError( f"UDL credential not found. Set either {_BASICAUTH_ENV} (direct " f"value) or {_SECRET_ARN_ENV} (AWS Secrets Manager ARN containing " f"a JSON object with a '{_SECRET_KEY}' key)." ) try: import boto3 # lazy import: optional dependency in [net] extra except ImportError as exc: raise RuntimeError( f"{_SECRET_ARN_ENV} is set but boto3 is not installed. Install " "the 'net' extra (pip install 'swxsoc_reach[net]') or set " f"{_BASICAUTH_ENV} directly." ) from exc session = boto3.session.Session(region_name=region_name) client = session.client(service_name="secretsmanager") response = client.get_secret_value(SecretId=secret_arn) secret = json.loads(response["SecretString"]) if _SECRET_KEY not in secret: raise RuntimeError( f"Secret at {_SECRET_ARN_ENV} does not contain required key " f"'{_SECRET_KEY}'." ) value = secret[_SECRET_KEY] # Mirror existing Lambda pattern: populate BASICAUTH for any # downstream code that reads the env var directly. os.environ[_BASICAUTH_ENV] = value log.info("Resolved UDL credential from AWS Secrets Manager") return value