docs(selfhost): document every docker-compose.yml var in .env.example - #6118
Conversation
docker-compose.yml's header calls .env.example "the exhaustive reference"
an operator copies to .env before running the stack. Cross-referencing
every ${VAR} interpolation against every name the sample file documents
found 18 real gaps -- knobs the stack reads that an operator could only
discover by reading docker-compose.yml itself:
- --profile backup, entirely undocumented: BACKUP_RETAIN,
BACKUP_INTERVAL_SECONDS, and the opt-in restore-drill pair
VERIFY_RESTORE_SCRATCH + LOOPOVER_VERIFY_SCRATCH_DATABASE_URL.
- The four AMS exporter source/reporting DB path overrides, and the
core exporter's LOOPOVER_REPORTING_DB output path.
- LOOPOVER_REPO_CONFIG_DIR, read by the always-on loopover service.
- The OTEL metrics-side siblings of the documented traces vars:
OTEL_METRICS_EXPORTER, OTEL_EXPORTER_OTLP_PROTOCOL,
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE.
- PROMETHEUS_RETENTION_TIME, REES_MEM_LIMIT (the one omission from the
otherwise-exhaustive *_MEM_LIMIT block), INSTALL_VISUAL_REVIEW.
- COMPOSE_PROJECT_NAME and TZ, which the drift guard below also requires
and which the issue's own "exhaustive" outcome covers.
Every documented default is the one docker-compose.yml already uses; no
default or behavior is invented, and each var is grouped under the
section it belongs to in the file's existing comment style.
The guard parses compose's interpolations and both reference files, then
asserts none is undocumented. Its negative lookbehind is load-bearing:
compose escapes a literal $ as $$, so $${GF_SECURITY_ADMIN_PASSWORD:-} is
resolved by the container's shell and is not a compose variable --
demanding .env.example document it would be wrong. Covers the pass case,
a stripped-fixture fail case, the $$-escape case, and the secrets/
README.md path, so this gap class cannot silently reopen.
Closes JSONbored#5814
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6118 +/- ##
==========================================
+ Coverage 86.41% 95.31% +8.89%
==========================================
Files 595 595
Lines 47083 47097 +14
Branches 15022 15030 +8
==========================================
+ Hits 40688 44890 +4202
+ Misses 4972 1476 -3496
+ Partials 1423 731 -692
Flags with carried forward coverage won't be shown. Click here to find out more. |
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-15 10:14:06 UTC
✅ Suggested Action - Approve/Merge
Review summary Nits — 4 non-blocking
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://gittensory.aethereal.dev/docs/loopover-commands 🧪 Experimental — new and may change. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
Summary
Closes #5814
docker-compose.yml's own header calls.env.example"the exhaustive reference" an operator copies to.envbefore running the stack. It wasn't. Cross-referencing every${VAR}interpolation compose actually uses against every name the sample file documents (liveNAME=and commented# NAME=alike) found 18 real gaps — knobs the stack reads that an operator could only discover by readingdocker-compose.ymlitself:--profile backup(entirely undocumented)BACKUP_RETAIN,BACKUP_INTERVAL_SECONDS, and the opt-in restore-drill pairVERIFY_RESTORE_SCRATCH+LOOPOVER_VERIFY_SCRATCH_DATABASE_URLLOOPOVER_AMS_*_SOURCE_DB/*_REPORTING_DBoverridesLOOPOVER_REPORTING_DB(the documentedLOOPOVER_REPORTING_SOURCE_DB's output sibling)loopoverserviceLOOPOVER_REPO_CONFIG_DIROTEL_METRICS_EXPORTER,OTEL_EXPORTER_OTLP_PROTOCOL,OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCEPROMETHEUS_RETENTION_TIME,REES_MEM_LIMIT,INSTALL_VISUAL_REVIEWCOMPOSE_PROJECT_NAME,TZEach is added in the file's existing
# NAME=default # explanation, --profile Xstyle, grouped under the section it belongs to (a new "Snapshot backups" block under the existing backup section, the OTEL metrics vars beside their traces siblings,REES_MEM_LIMITin the*_MEM_LIMITblock, etc.). No default or behavior is invented — every documented value is the onedocker-compose.ymlalready uses (BACKUP_RETAIN=7,PROMETHEUS_RETENTION_TIME=90d, …), andPROMETHEUS_RETENTION_TIME's note summarizes compose's own stated rationale rather than inventing one.Two deviations from the issue's list, both deliberate
COMPOSE_PROJECT_NAMEandTZare included though the issue's enumeration omits them. They are real compose interpolations (${COMPOSE_PROJECT_NAME:-loopover}inpromtail,${TZ:-UTC}inn8n), so the drift guard this issue requires fails unless they're documented too. Documenting them is what makes the file exhaustive — the issue's own Expected Outcome.GF_SECURITY_ADMIN_PASSWORD/N8N_BASIC_AUTH_PASSWORDare not included, though a naive grep suggests they're missing. They appear as$${VAR}— compose escapes a literal$as$$, so those reach the container's shell and are resolved there. They are not compose variables, and documenting them as.envknobs would be wrong. The guard's regex encodes this (see below).Scope
docs(selfhost): …)..env.exampleis a sample file; every line added is a comment.CONTRIBUTING.md; nosite//CNAME/lovablechanges; no changelog edit.Validation
git diff --checkclean..env.examplemetric-name guard — 6 tests passed..env.exampleand the invariant reports exactly the 18 pre-fix gaps ([ 'BACKUP_INTERVAL_SECONDS', …(17) ]); restored → green.main(which already carries fix(selfhost): correct stale gittensory_ metric names in .env.example #6079's.env.examplechange — no conflict).The guard (
test/unit/docker-compose-env-example-parity.test.ts) is a distinct check fromnpm run selfhost:env-reference, which scansprocess.envreads undersrc/selfhost/**and never looks atdocker-compose.ymlor.env.example. It covers, per the issue's requirement of both a pass and a fail case:.env.exampleorsecrets/README.md..env.exampleis reported — proving it catches drift, not just that it passes today.$$-escape:$${FOO}is ignored,${BAR}is not.*_FILEvar counts as documented viasecrets/README.md, and is reported when documented in neither.If any required check was skipped, explain why:
test:cinot run end-to-end locally (Linux-only steps on Windows)..env.exampleis a config file outsidecoverage.include, so the patch gate does not apply to the documentation edit; the new guard lives undertest/unit/**. The guard's own logic is fully exercised by the five cases above (both sides of every branch: documented/undocumented, escaped/unescaped, secrets/not-secrets).Safety
.env.example→.envyields byte-identical runtime behavior to today — the defaults documented are the ones compose already applies.