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.
$ 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 , 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.
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 and security policy 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. The versioned JSON contract is scan-result.schema.json.
python -m venv .venv
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 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.