Files
wyndham-ARR/arr_processing/config.py
2026-07-29 16:38:05 +08:00

63 lines
2.2 KiB
Python

"""Environment-only configuration for authenticated Agent result writeback."""
from __future__ import annotations
import base64
import binascii
import os
from dataclasses import dataclass
from typing import Mapping, Optional
from arr_ingestion.contracts import OPAQUE_ID_RE
from arr_processing.errors import ProcessingError
from arr_processing.signatures import SignedResultCodec
@dataclass(frozen=True)
class ResultVerificationConfig:
key_id: str
secret: bytes
max_age_seconds: int = 600
@classmethod
def from_environment(
cls,
environment: Optional[Mapping[str, str]] = None,
) -> "ResultVerificationConfig":
values = environment if environment is not None else os.environ
key_id = str(values.get("ARR_AGENT_RESULT_HMAC_KEY_ID", "")).strip()
encoded = str(values.get("ARR_AGENT_RESULT_HMAC_KEY_B64", "")).strip()
age_text = str(values.get("ARR_AGENT_RESULT_MAX_AGE_SECONDS", "600")).strip()
if not OPAQUE_ID_RE.fullmatch(key_id):
raise ProcessingError(
"PROCESSING_SIGNATURE_CONFIG_MISSING",
"Agent result signing key identifier is missing",
)
try:
secret = base64.b64decode(encoded, validate=True)
max_age = int(age_text)
except (binascii.Error, ValueError):
raise ProcessingError(
"PROCESSING_SIGNATURE_CONFIG_INVALID",
"Agent result signing configuration is invalid",
) from None
if len(secret) < 32 or not 1 <= max_age <= 3600:
raise ProcessingError(
"PROCESSING_SIGNATURE_CONFIG_INVALID",
"Agent result signing configuration is invalid",
)
return cls(key_id=key_id, secret=secret, max_age_seconds=max_age)
def verifier(self) -> SignedResultCodec:
return SignedResultCodec(
{self.key_id: self.secret},
max_age_seconds=self.max_age_seconds,
)
def signer(self) -> SignedResultCodec:
return SignedResultCodec(
{self.key_id: self.secret},
signing_key_id=self.key_id,
max_age_seconds=self.max_age_seconds,
)