How the Config Class Manages Credentials Securely in Agent-Reach

The Config class stores API keys and tokens in a user-specific YAML file with 0o600 permissions, supports environment variable fallbacks, and masks sensitive values in logs to prevent credential leakage.

The Config class in the Panniantong/Agent-Reach repository provides a lightweight, security-focused configuration manager for handling sensitive credentials. Located in agent_reach/config.py, this implementation combines filesystem-level protections with runtime safeguards to ensure API keys and authentication tokens remain confidential while remaining accessible to the application.

Secure Filesystem Storage

The Config class implements defense-in-depth at the storage layer by creating a dedicated hidden directory and enforcing strict file permissions.

Dedicated Hidden Directory

On first initialization, the class creates ~/.agent-reach to isolate credentials from the rest of the filesystem. The CONFIG_DIR constant defines this path as Path.home() / ".agent-reach", and the _ensure_dir() method creates the folder using mkdir(parents=True, exist_ok=True). This prevents accidental exposure through directory listings and keeps sensitive data out of version-controlled project directories.

Atomic File Permissions

When writing credentials to disk, the save() method in agent_reach/config.py uses os.open with stat.S_IRUSR | stat.S_IWUSR flags to create files with mode 0o600 (read/write for owner only). This ensures that even if the file is created in a shared environment, other users cannot read the contents. For Windows or edge cases where these POSIX flags are unavailable, the code catches OSError and falls back to standard file operations while preserving the write operation.

Flexible Credential Resolution

The class provides multiple access patterns to balance security with convenience, allowing users to avoid persisting secrets on disk when preferred.

Environment Variable Fallback

The get() method implements a lookup hierarchy that checks the in-memory dictionary first, then falls back to environment variables using os.environ.get(key.upper()). This allows operators to export sensitive values via shell environment variables (e.g., export OPENAI_API_KEY=sk-...) rather than writing them to the YAML file, supporting ephemeral deployment scenarios and CI/CD pipelines.

Feature-Centric Validation

Rather than requiring manual credential checking, the is_configured() method validates that all required secrets for a specific feature are present. The FEATURE_REQUIREMENTS dictionary maps feature names (like "twitter_xreach") to their required key lists (e.g., ["twitter_auth_token", "twitter_ct0"]). This prevents runtime errors that could expose missing credentials through stack traces or debug output.

Runtime Data Protection

The Config class includes safeguards against accidental credential exposure during logging and debugging.

When converting configuration to a dictionary for display, the to_dict() method masks any value where the key contains "key", "token", "password", or "proxy". These sensitive values are truncated to the first 8 characters, ensuring that debug logs, error reports, and console output never reveal complete secrets while still allowing partial verification that a value is set.

Practical Implementation Example

from agent_reach.config import Config

# Load (or create) the user config

cfg = Config()

# Store a new API key – file is written with 0o600 permissions

cfg.set("openai_api_key", "sk-XXXXXXXXXXXXXXXXXXXX")

# Retrieve a key – prefers the file, then falls back to an env var

api_key = cfg.get("openai_api_key")

# Quick feature check – returns True only if required secrets exist

if cfg.is_configured("openai_whisper"):
    print("OpenAI Whisper is ready to use")
else:
    print("Missing OpenAI credentials")

# Print a safe view (secret values are truncated)

print(cfg.to_dict())

Summary

  • The Config class creates a dedicated ~/.agent-reach directory with restricted permissions to isolate credentials
  • File writes use os.open with stat.S_IRUSR | stat.S_IWUSR to enforce 0o600 mode on POSIX systems, with graceful fallback for Windows
  • Environment variables take precedence over file storage via os.environ.get(key.upper()) lookups in the get() method
  • The to_dict() method masks sensitive values to prevent accidental credential exposure in logs and debug output
  • Feature requirements validation via is_configured() ensures all necessary credentials are present before API calls

Frequently Asked Questions

Where does Agent-Reach store configuration files?

The Config class stores data in ~/.agent-reach/config.yaml within a hidden directory created under the user's home path. This location is defined by CONFIG_DIR = Path.home() / ".agent-reach" in agent_reach/config.py, and the folder is created automatically on first use if it does not exist.

What file permissions does Agent-Reach use for credential storage?

The save() method creates files with mode 0o600 (read/write for owner only) using os.open with stat.S_IRUSR | stat.S_IWUSR flags. On Windows or systems where these POSIX flags are unavailable, it catches OSError and falls back to standard file writes without terminating the operation.

Can I use environment variables instead of the config file?

Yes. The get() method checks for environment variables using the uppercase key name before falling back to the YAML file. Set export OPENAI_API_KEY=your_key to override file-based credentials and avoid persisting secrets on disk.

How does Agent-Reach prevent secrets from appearing in logs?

The to_dict() method automatically masks values for any key containing "key", "token", "password", or "proxy" by truncating them to the first 8 characters. This ensures that full credentials never appear in debug output, stack traces, or console logs when the configuration object is printed.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →