# How dcg Resolves Conflicts Between Multiple Configuration Files: Layered Priority Explained

> Learn how dcg resolves config conflicts with its layered priority system. Discover how environment variables override system, user, and explicit config files for ultimate control.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: internals
- Published: 2026-07-22

---

**dcg resolves configuration conflicts by applying a strict five-layer hierarchy where environment variables override explicit config files, which override user configs, which override system configs, with compiled defaults serving as the final fallback.**

The **Destructive Command Guard** (`dcg`) implements a deterministic, security-first approach to configuration management in the `Dicklesworthstone/destructive_command_guard` repository. When multiple configuration sources define the same setting, dcg's layered configuration system uses a fixed precedence order to ensure predictable behavior and prevent security downgrades. This design guarantees that sensitive settings from higher-trust sources always take precedence over lower-trust alternatives.

## The Five-Layer Configuration Hierarchy

dcg builds its runtime `Config` struct by loading sources in a specific sequence, with each layer overwriting values from the previous one. The resolution order implemented in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) prioritizes user intent and system security:

### Layer 1: Environment Variables (Highest Priority)

**Environment variables** prefixed with `DCG_` represent the highest-priority configuration source. Any setting exposed via environment overrides all file-based configurations, making them ideal for temporary overrides or containerized deployments. For example, setting `DCG_POLICY_DEFAULT_MODE=warn` immediately changes the policy behavior regardless of config file contents.

### Layer 2: Explicit Config File (DCG_CONFIG)

When users specify a **trusted explicit config file** via the `DCG_CONFIG` environment variable, dcg loads this file with elevated priority. This layer overrides the user-wide and system-wide configurations but remains subordinate to direct `DCG_` environment variables. The file path specified in `DCG_CONFIG` is treated as explicitly trusted by the operator.

### Layer 3: User Config (XDG Directories)

dcg searches for user-specific configuration in standard XDG directories. It first checks `$XDG_CONFIG_HOME/dcg/config.toml`, falling back to `~/.config/dcg/config.toml` if the variable is unset. This **user config** layer provides personalized defaults that apply across all repositories for the current user, overriding system-wide settings but yielding to explicit configs and environment variables.

### Layer 4: System Config (/etc/dcg/)

The **system config** at [`/etc/dcg/config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main//etc/dcg/config.toml) provides global defaults for all users on the host. Administrators use this layer to establish baseline security policies across multi-user systems. According to the source comments in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs), this layer serves as the foundation that higher-priority sources build upon or override.

### Layer 5: Compiled Defaults (Fallback)

**Compiled defaults** are hard-coded values embedded in the binary during compilation. These values activate only when no other configuration layer provides a specific setting, ensuring the application functions even in the absence of any configuration files.

## Special Handling for Repository-Local .dcg.toml Files

A repository-local file named **[`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml)** receives special treatment due to security considerations. Because this file can be contributed by anyone in a shared repository, dcg treats it as **untrusted** by default. According to the implementation in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs), auto-discovered [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) files **cannot weaken security**: they may only add protective rules and never introduce allow-list entries, disable packs, or change security-critical paths.

Users can voluntarily promote a [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) to trusted status by setting `DCG_CONFIG=.dcg.toml`. In this case, the file moves from the auto-discovered untrusted layer to the explicit config layer (Layer 2), gaining the ability to modify security settings.

## The Merge Process and Conflict Resolution

When dcg initializes via `Config::load()` (called from [`src/main.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/main.rs)), it executes a sequential merge process defined in `Config::from_sources`. The implementation follows this pattern:

```rust
let env_cfg = Config::from_env();                // 1. Env vars
let explicit_cfg = Config::from_path(env_cfg_path); // 2. DCG_CONFIG
let user_cfg = Config::from_path(user_path);     // 3. User config
let system_cfg = Config::from_path(system_path); // 4. System config
let defaults = Config::default();                // 5. Compiled defaults

let final_cfg = defaults
    .merge(system_cfg)
    .merge(user_cfg)
    .merge(explicit_cfg)
    .merge(env_cfg);

```

The `merge` method copies any defined fields from the right-hand argument onto the left, respecting the precedence order. When conflicts arise—such as the same key existing in both user and system configs—the value from the **higher-priority layer** wins. This deterministic approach ensures identical runtime configurations given the same set of files and environment variables.

### Practical Configuration Examples

Override the default policy mode using environment variables:

```bash

# Highest priority - overrides any config file

export DCG_POLICY_DEFAULT_MODE="warn"
dcg rm -rf /sensitive/path

```

Use an explicit trusted configuration:

```bash

# Promotes /home/alice/strict-dcg.toml to Layer 2 priority

export DCG_CONFIG="/home/alice/strict-dcg.toml"
dcg git reset --hard

```

User-wide configuration fallback:

```toml

# ~/.config/dcg/config.toml

policy_default_mode = "deny"
packs = { enabled = ["core.git", "core.filesystem"] }

```

System-wide baseline defaults:

```toml

# /etc/dcg/config.toml

policy_default_mode = "log"

```

## Security Safeguards in Config Loading

Before merging layers, dcg applies security constraints through `read_config_file_bounded` in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs). This function enforces size limits and performs symlink-safety checks to prevent configuration injection attacks. Additionally, [`src/allowlist.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/allowlist.rs) implements trust verification ensuring that allow-list entries are **only** accepted from trusted layers (user, system, or explicit configs), never from auto-discovered [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) files.

The [`src/cli.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/cli.rs) module provides command-line flags that map internally to environment variables, preserving the same precedence hierarchy while offering convenient runtime overrides.

## Summary

- **dcg uses a five-layer hierarchy**: Environment variables → Explicit config → User config → System config → Compiled defaults.
- **Higher layers overwrite lower layers**: The `merge` method in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) implements deterministic conflict resolution where the most recent (highest priority) value persists.
- **Repository configs are untrusted**: Auto-discovered [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) files cannot weaken security; they only add protective rules unless explicitly promoted via `DCG_CONFIG`.
- **Security-first loading**: Size limits and symlink checks in `read_config_file_bounded` prevent exploitation during config file reading.
- **Predictable behavior**: Given the same files and environment variables, `Config::load()` produces identical runtime configurations every time.

## Frequently Asked Questions

### What happens if the same key exists in user and system config?

The user config value takes precedence. According to the precedence hierarchy in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs), user configuration (Layer 3) ranks higher than system configuration (Layer 4). When the `merge` method processes these layers, values from `user_cfg` replace those from `system_cfg`, ensuring individual users can override administrative defaults without modifying system files.

### Can a .dcg.toml file disable security features or add allow-list entries?

No, not when auto-discovered. The source code explicitly treats [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) as untrusted because it may originate from external contributors. As implemented in the configuration loading logic, these files **cannot weaken security**—they may only add protective rules. Allow-list entries and security-disabling settings are rejected from auto-discovered [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) files; they are only accepted from trusted layers (user, system, or explicit configs via `DCG_CONFIG`).

### How do I override a specific setting without modifying config files?

Set a `DCG_`-prefixed environment variable. Environment variables constitute Layer 1 (highest priority) in dcg's configuration hierarchy and override all file-based settings. For example, `export DCG_POLICY_DEFAULT_MODE=interactive` immediately changes the policy behavior for that shell session without touching any TOML files. The [`src/cli.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/cli.rs) module also provides flags that map to these environment variables for convenience.

### Where does dcg look for configuration files by default?

dcg searches four specific locations in order of priority: first, the path specified in `DCG_CONFIG` (explicit Layer 2); second, `$XDG_CONFIG_HOME/dcg/config.toml` or `~/.config/dcg/config.toml` (user Layer 3); third, [`/etc/dcg/config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main//etc/dcg/config.toml) (system Layer 4); and finally, auto-discovered [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) in the current directory (untrusted, restricted). The `Config::from_path` and `read_config_file_bounded` functions in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) handle this discovery and loading process with appropriate security checks.