This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
Configuration System
Loading…
Configuration System
Relevant source files
- src/config.rs
- src/config/app_config.rs
- src/config/config_manager.rs
- src/config/credential_manager.rs
- src/models/cik.rs
- src/models/investment_company.rs
- src/parsers/parse_nport_xml.rs
- tests/config_manager_tests.rs
This document describes the configuration management system in the Rust sec-fetcher application. The configuration system provides a flexible, multi-source approach to managing application settings including SEC API credentials, request throttling parameters, and cache directories.
For information about how the configuration integrates with the caching system, see Caching & Storage System. For details on credential storage mechanisms, see the credential management section below.
Overview
The configuration system consists of three primary components:
| Component | Purpose | File Location |
|---|---|---|
AppConfig | Data structure holding all configuration fields with JSON schema support | src/config/app_config.rs:16-41 |
ConfigManager | Loads, merges, and validates configuration from multiple sources | src/config/config_manager.rs:95-101 |
CredentialManager | Handles email credential storage and retrieval via system keyring | src/config/credential_manager.rs:19-22 |
The system supports configuration from four sources with increasing priority:
- Default values - Hard-coded defaults in
AppConfig::default()src/config/app_config.rs:43-62 - Environment Variables -
SEC_FETCHER_EMAIL,SEC_FETCHER_APP_NAME, etc. src/config/config_manager.rs:56-88 - TOML configuration file - User-specified settings loaded from disk src/config/config_manager.rs:168-171
- Interactive prompts - Credential collection when running in interactive mode src/config/credential_manager.rs:81-127
Sources: src/config/app_config.rs:16-62 src/config/config_manager.rs:56-155
Configuration Structure
AppConfig Fields
All fields in AppConfig are wrapped in Option<T> to support partial configuration and merging strategies. The #[merge(strategy = overwrite_option)] attribute ensures that non-None values from user configuration always replace default values.
Sources: src/config/app_config.rs:16-41 src/config/app_config.rs:43-62
Configuration Loading Flow
ConfigManager Initialization
Sources: src/config/config_manager.rs:107-182 src/config/credential_manager.rs:81-127
Configuration File Format
TOML Structure
The configuration file uses TOML format with strict schema validation. Any unrecognized keys will cause a descriptive error listing all valid keys and their types using schemars integration.
Example configuration file (sec_fetcher_config.toml):
Configuration File Locations
The system searches for configuration files in the following order:
| Priority | Location | Description |
|---|---|---|
| 1 | User-provided path | Passed to ConfigManager::from_config(Some(path)) |
| 2 | System config directory | ~/.config/sec_fetcher_config.toml (Unix) |
| 3 | Current directory | ./sec_fetcher_config.toml |
Sources: src/config/config_manager.rs:103-104 src/config/config_manager.rs:129-131 src/config/config_manager.rs:166-170
Credential Management
Email Credential Requirement
The SEC EDGAR API mandates a valid email address in the HTTP User-Agent header for identification. The configuration system resolves this using the following precedence:
Interactive Mode Detection:
graph TD
Start["ConfigManager Resolution"]
CheckArg["App Identity Override?"]
CheckFile["Email in TOML Config?"]
CheckEnv["SEC_FETCHER_EMAIL Env Var?"]
CheckInteractive{"is_interactive_mode()?"}
PromptUser["CredentialManager::from_prompt()"]
ReadKeyring["Read from system keyring"]
PromptInput["Prompt user for email"]
SaveKeyring["Save to keyring"]
SetEmail["Set email in ConfigManager"]
Error["Return Error:\nCould not obtain email credential"]
Start --> CheckArg
CheckArg -->|No| CheckFile
CheckFile -->|No| CheckEnv
CheckEnv -->|No| CheckInteractive
CheckInteractive -->|Yes| PromptUser
CheckInteractive -->|No| Error
PromptUser --> ReadKeyring
ReadKeyring -->|Found| SetEmail
ReadKeyring -->|Not found| PromptInput
PromptInput --> SaveKeyring
SaveKeyring --> SetEmail
- Returns
trueifstdin/stdoutare a terminal (TTY) src/config/credential_manager.rs:82-84 - Can be overridden via
set_interactive_mode_override()for testing tests/config_manager_tests.rs81
Sources: src/config/config_manager.rs:41-56 src/config/credential_manager.rs:32-76
Configuration Merging Strategy
Merge Behavior
The AppConfig struct uses the merge crate with a custom overwrite_option strategy defined in src/config/app_config.rs:8-12:
Merge Rules:
Some(new_value)always replacesSome(old_value)src/config/app_config.rs:9-11Some(new_value)always replacesNoneNonenever replacesSome(old_value)
This ensures user-provided values take absolute precedence over defaults while allowing partial configuration.
Sources: src/config/app_config.rs:8-12 src/config/config_manager.rs:172-182
Schema Validation and Error Handling
Invalid Key Detection
The configuration system uses #[serde(deny_unknown_fields)] to reject unknown keys in TOML files src/config/app_config.rs15 When an invalid key is detected, the error message includes a complete list of valid keys with their types extracted via schemars:
Example error output:
graph LR
TOML["TOML File with\ninvalid_key"]
Deserialize["config.try_deserialize()"]
ExtractSchema["AppConfig::get_valid_keys()"]
Schema["schemars::schema_for!(AppConfig)"]
FormatError["Format error message with\nvalid keys and types"]
TOML --> Deserialize
Deserialize -->|Error| ExtractSchema
ExtractSchema --> Schema
Schema --> FormatError
FormatError --> Error["Return descriptive error"]
unknown field `invalid_key`, expected one of `email`, `app_name`, `app_version`, `max_concurrent`, `min_delay_ms`, `max_retries`, `cache_base_dir`
Valid configuration keys are:
- email (String | Null)
- app_name (String | Null)
- app_version (String | Null)
- max_concurrent (Integer | Null)
- min_delay_ms (Integer | Null)
- max_retries (Integer | Null)
- cache_base_dir (String | Null)
Sources: src/config/app_config.rs:69-83 src/config/config_manager.rs:175-182 tests/config_manager_tests.rs:154-181
Usage Examples
Loading Configuration
Default configuration path:
Custom configuration path:
Overriding App Identity:
Sources: src/config/config_manager.rs:108-110 src/config/config_manager.rs:129-131 src/config/config_manager.rs:151-155
Cache Isolation
The ConfigManager manages the lifetime of the cache directory. If cache_base_dir is not provided in the configuration, it creates a unique tempfile::TempDir src/config/app_config.rs:45-48
This ensures that tests and ephemeral runs have fully isolated cache storage that is cleaned up when the ConfigManager is dropped src/config/app_config.rs:47-48
Sources: src/config/app_config.rs:43-62 src/config/config_manager.rs:98-100
Testing
Test Coverage
The configuration system includes unit tests in tests/config_manager_tests.rs covering:
| Test Function | Purpose |
|---|---|
test_load_custom_config | Verifies loading from custom TOML file path tests/config_manager_tests.rs46 |
test_fails_on_invalid_key | Validates schema enforcement and error messages tests/config_manager_tests.rs154 |
test_email_from_env_var_non_interactive | Checks SEC_FETCHER_EMAIL resolution tests/config_manager_tests.rs103 |
test_config_file_email_takes_precedence | Validates priority of TOML over Env Vars tests/config_manager_tests.rs130 |
Sources: tests/config_manager_tests.rs:1-207
Dismiss
Refresh this wiki
Enter email to refresh