Skip to content

Configuration

Two separate mechanisms, deliberately kept apart. Config loads the YAML file that describes cryptographic defaults — query plans, bounds, budget limits. Settings reads deployment concerns from the environment: endpoints, credentials, limits.

YAML configuration

config

ConfigError

ConfigError(
    message: str,
    config_key: str | None = None,
    error_code: str | None = None,
)

Bases: ConfigurationError

Raised when there are configuration-related errors.

Initialize configuration error.

Parameters:

Name Type Description Default
message str

Human-readable error message

required
config_key str | None

The configuration key that caused the error

None
error_code str | None

Optional error code for programmatic handling

None
Source code in src/cryptography_manager/exceptions.py
def __init__(
    self,
    message: str,
    config_key: str | None = None,
    error_code: str | None = None,
) -> None:
    """Initialize configuration error.

    Args:
        message: Human-readable error message
        config_key: The configuration key that caused the error
        error_code: Optional error code for programmatic handling
    """
    super().__init__(message, error_code)
    self.config_key = config_key

Config

Config(config_data: dict[str, Any] | None = None)

Initialize the configuration.

Parameters:

Name Type Description Default
config_data dict[str, Any] | None

Optional initial configuration data

None
Source code in src/cryptography_manager/config/config.py
def __init__(self, config_data: dict[str, Any] | None = None) -> None:
    """Initialize the configuration.

    Args:
        config_data: Optional initial configuration data
    """
    self._config = deepcopy(DEFAULT_CONFIG)
    if config_data:
        self._merge_config(config_data)
load_from_file
load_from_file(file_path: str | Path) -> None

Load configuration from a file.

Parameters:

Name Type Description Default
file_path str | Path

Path to the configuration file

required

Raises:

Type Description
ConfigError

If file cannot be loaded or parsed

Source code in src/cryptography_manager/config/config.py
def load_from_file(self, file_path: str | Path) -> None:
    """Load configuration from a file.

    Args:
        file_path: Path to the configuration file

    Raises:
        ConfigError: If file cannot be loaded or parsed
    """
    file_path = Path(file_path)

    if not file_path.exists():
        raise ConfigError(f"Configuration file not found: {file_path}")

    try:
        with open(file_path, "r", encoding="utf-8") as f:
            if file_path.suffix.lower() in [".yaml", ".yml"]:
                config_data = yaml.safe_load(f)
            elif file_path.suffix.lower() == ".json":
                config_data = json.load(f)
            else:
                raise ConfigError(
                    f"Unsupported configuration file format: {file_path.suffix}"
                )

        if not isinstance(config_data, dict):
            raise ConfigError(
                "Configuration file must contain a dictionary"
            )

        self._merge_config(config_data)

    except yaml.YAMLError as e:
        raise ConfigError(f"Invalid YAML in configuration file: {e}")
    except json.JSONDecodeError as e:
        raise ConfigError(f"Invalid JSON in configuration file: {e}")
    except Exception as e:
        raise ConfigError(f"Error loading configuration file: {e}")
get_submodule_config
get_submodule_config(submodule: str) -> dict[str, Any]

Return one top-level configuration section.

Parameters:

Name Type Description Default
submodule str

Name of the section, e.g. differential_privacy.

required

Returns:

Type Description
dict[str, Any]

The section, or an empty mapping when it is absent. Returning an

dict[str, Any]

empty mapping rather than None keeps every caller's

dict[str, Any]

section["key"] access from failing with an unhelpful

dict[str, Any]

TypeError when configuration is simply missing.

Raises:

Type Description
ConfigError

If the section cannot be read.

Source code in src/cryptography_manager/config/config.py
def get_submodule_config(self, submodule: str) -> dict[str, Any]:
    """Return one top-level configuration section.

    Args:
        submodule: Name of the section, e.g. ``differential_privacy``.

    Returns:
        The section, or an empty mapping when it is absent. Returning an
        empty mapping rather than ``None`` keeps every caller's
        ``section["key"]`` access from failing with an unhelpful
        ``TypeError`` when configuration is simply missing.

    Raises:
        ConfigError: If the section cannot be read.
    """
    try:
        section = self._config.get(submodule)
    except Exception as e:
        raise ConfigError(f"Error loading submodule configuration: {e}")
    if section is None:
        return {}
    if not isinstance(section, dict):
        raise ConfigError(
            f"Configuration section '{submodule}' must be a mapping, "
            f"got {type(section).__name__}"
        )
    return section

Defaults

defaults

Default configuration values for the Cryptography Manager.

This module defines all default configuration values used throughout the library, organized by component and feature area.

Environment settings

settings

Environment-derived runtime settings.

These are deployment concerns -- where to send audit records, how to verify tokens, where to keep state -- as opposed to the cryptographic parameters in the YAML configuration file. Keeping them apart means the same config file can be mounted into different environments without editing.

Field names use a CRM_ prefix, but the unprefixed names some deployments already set are accepted as aliases so nothing has to be renamed to adopt this.

Settings

Bases: BaseSettings

Runtime settings resolved from the environment.

issuer_url property
issuer_url: str | None

Full issuer URL, including the realm segment when one is set.

audit_targets property
audit_targets: dict[str, str]

Configured downstream audit sinks, keyed by name.

get_settings cached

get_settings() -> Settings

Return the process-wide settings, read from the environment once.

Source code in src/cryptography_manager/config/settings.py
@lru_cache(maxsize=1)
def get_settings() -> Settings:
    """Return the process-wide settings, read from the environment once."""
    return Settings()