# Show HN: ConfigLedger -Find configuration drift across code, CI, Docker and docs

> Source: <https://github.com/DevFoundry-labs/configledger/>
> Published: 2026-08-11 05:22:30+00:00

**Find configuration drift across code, examples, CI, containers, deployment YAML, and docs—without collecting secret values.**

ConfigLedger is a local, deterministic CLI for answering questions that are surprisingly hard in a real repository:

- Where is
`DATABASE_URL`

consumed, delivered, exemplified, and documented? - Which active keys have no documented setup path?
- Which sample or deployment defaults disagree?
- Which example keys are unused?
- Did someone put a literal value next to a sensitive-looking key?

It runs offline, executes no repository code, needs no account, and sends nothing to an AI service.

``` bash
$ configledger scan examples/demo --no-cache --fail-on none
ConfigLedger
Scanned 4 artifacts; found 4 configuration keys.
Findings: 1 critical, 2 high, 2 medium, 1 low.

[CRITICAL] config.sensitive-literal — SUPPORT_TOKEN
  SUPPORT_TOKEN looks sensitive and has a non-placeholder literal in an example surface.
  - .env.example:3 (example)
  - app.py:5 (consumption)

[HIGH] config.undefined-consumption — ANALYTICS_KEY
  ANALYTICS_KEY is consumed but no definition, example, or delivery surface was found.
  - app.py:4 (consumption)
```

Environment and configuration keys are duplicated across source code, `.env.example`

, Docker, CI, Kubernetes, and documentation. Format-specific linters see one file type; secret scanners look for leaked values. ConfigLedger builds a source-linked, per-key provenance record across all of those surfaces and evaluates transparent drift rules.

ConfigLedger does **not** replace a secret manager, configuration loader, or vulnerability scanner. It deliberately analyzes names and safe metadata—not runtime values.

ConfigLedger requires Python 3.12 or newer.

```
python -m pip install configledger
```

For development or before the first package-index release:

```
git clone https://github.com/DevFoundry-labs/configledger.git
cd configledger
python -m pip install .
```

Scan the current repository:

```
configledger scan .
```

Try the reproducible included demo without letting findings change the shell exit code:

```
configledger scan examples/demo --no-cache --fail-on none
```

Export machine-readable or review-friendly output:

```
configledger scan . --format json --output configledger-report.json
configledger scan . --format markdown --output configledger-report.md
configledger scan . --format schema --output .env.generated.example
```

Inspect one key:

```
configledger show DATABASE_URL .
```

| Surface | Evidence recognized in v0.1 |
|---|---|
| Python | `os.getenv` , `os.environ` , Pydantic-style settings and aliases |
| JavaScript / TypeScript | `process.env.KEY` , indexed access, `import.meta.env.KEY` |
| Dotenv examples | `.env.example` , `.env.sample` , `.env.template` |
| Dockerfile | `ARG` , `ENV` , and variable references |
| Docker Compose / YAML | `environment` , `env` , and interpolated variables |
| GitHub Actions | `env` , `vars` , and `secrets` references |
| Kubernetes-like YAML | `env` entries and `name` keys (confidence-tagged) |
| Markdown | Backticked keys, tables, and key/value-style references |

Unsupported or ambiguous syntax is reported as a diagnostic or omitted. ConfigLedger never treats incomplete static evidence as proof that runtime configuration is safe.

| Rule | Default severity | Meaning |
|---|---|---|
`config.undefined-consumption` |
High | A consumed key has no definition, example, or delivery evidence. |
`config.unused-declaration` |
Low | A defined/example key has no consumption or delivery evidence. |
`config.undocumented` |
Medium | An active key has no Markdown documentation evidence. |
`config.default-drift` |
High | Non-secret default fingerprints disagree across surfaces. |
`config.sensitive-literal` |
Critical | A sensitive-looking key has a non-placeholder literal in an example. |

List rules from the installed version:

```
configledger rules
```

Create `.configledger.toml`

at the repository root:

```
[scan]
ignore_paths = ["vendor/**", "generated/**"]
ignore_keys = ["TEST_ONLY_*"]
internal_keys = ["CI", "INTERNAL_*"]
max_files = 5000
max_file_bytes = 1000000
max_total_bytes = 25000000

[rules]
disabled = ["config.unused-declaration"]
fail_on = "high" # info, low, medium, high, critical, or none

[rules.severity]
"config.undocumented" = "low"
```

Command-line `--fail-on`

overrides the policy for that run. See [configuration reference](/DevFoundry-labs/configledger/blob/main/docs/configuration.md).

Baselines contain finding fingerprints, not configuration values:

```
configledger baseline create .configledger-baseline.json .
configledger baseline compare .configledger-baseline.json .
```

The compare command exits with status 1 when new fingerprints appear.

| Code | Meaning |
|---|---|
| 0 | Scan completed and no finding met the failure threshold. |
| 1 | Findings met the threshold, a key was not found, or baseline comparison found new findings. |
| 2 | Invalid path, policy, report path, or other usage error. |
| 3 | Reserved for unexpected internal failures. |

`.env`

,`.env.local`

, private keys, binaries, and common dependency/build directories are excluded before reading.- Example/deployment literals are represented by hashes and redacted excerpts; raw values are not stored in reports or SQLite.
- Repository modules, scripts, containers, and workflows are never executed.
- Discovery is bounded and rejects out-of-root symlink reads.
- Core operation is offline and has no telemetry or AI provider.

Read the [threat model](/DevFoundry-labs/configledger/blob/main/docs/threat-model.md) and [security policy](/DevFoundry-labs/configledger/blob/main/SECURITY.md) before scanning untrusted repositories in sensitive environments.

```
safe discovery → format extractors → normalized occurrences
      → per-key provenance → deterministic rules → reports / SQLite cache
```

The CLI, library API, persistence model, and reporter boundaries are described in [architecture.md](/DevFoundry-labs/configledger/blob/main/docs/architecture.md). The versioned JSON contract is [scan-result.schema.json](/DevFoundry-labs/configledger/blob/main/schemas/scan-result.schema.json).

```
python -m venv .venv
# Windows: .venv\Scripts\activate
# macOS/Linux: source .venv/bin/activate
python -m pip install -e ".[dev]"
ruff format --check .
ruff check .
mypy src
pytest --cov=configledger --cov-report=term-missing
python -m build
```

See [CONTRIBUTING.md](/DevFoundry-labs/configledger/blob/main/CONTRIBUTING.md) for extractor and rule contribution guidance.

- v0.1: Local inventory, six extractor families, five rules, four report formats, baselines, SQLite cache.
- v0.2: SARIF, richer framework adapters, GitHub Action annotations, ignore explanations.
- v0.3: Stable extractor SDK and community compatibility fixtures.

The project will remain local-first and deterministic. New features must improve configuration provenance rather than turn ConfigLedger into a secret manager or generic code-intelligence platform.

Apache License 2.0. See [LICENSE](/DevFoundry-labs/configledger/blob/main/LICENSE).
