from __future__ import annotations import logging import os logger = logging.getLogger(__name__) def read_secret_file(filepath: str) -> str: if not filepath: raise ValueError("filepath cannot be empty") real_path = os.path.realpath(filepath) if real_path != os.path.abspath(filepath): raise ValueError("Secret file path contains symlinks, which is not allowed") try: with open(filepath, encoding="utf-8") as f: content = f.read() except FileNotFoundError: raise ValueError(f"Secret file not found: {filepath}") except PermissionError: raise ValueError(f"Permission denied reading secret file: {filepath}") return content.strip() def resolve_credential( direct_value: str | None, file_path: str | None, env_var: str | None = None, ) -> str: if direct_value: return direct_value if file_path: return read_secret_file(file_path) if env_var: val = os.getenv(env_var, "") if val: return val return "" def resolve_credential_with_source( direct_value: str | None, file_path: str | None, env_var: str | None = None, ) -> tuple[str, str]: if direct_value: return direct_value, "config" if file_path: return read_secret_file(file_path), "secretFile" if env_var: val = os.getenv(env_var, "") if val: return val, "env" return "", "none"