fix(compose): map the EVENT_LOOP_MONITOR_* knobs into the api service (#3236) - #3238
Merged
ToddHebebrand merged 2 commits intoAug 8, 2026
Conversation
…LanternOps#3236) `EVENT_LOOP_MONITOR_INTERVAL_MS`, `EVENT_LOOP_STARVATION_WARN_MS` and `EVENT_LOOP_MONITOR_DISABLED` are documented as working tuning knobs in deploy/environment.mdx and read at services/eventLoopMonitor.ts, but neither compose file listed them in the api service's `environment:` block. Compose only interpolates variables named there, so setting any of the three in `.env` under the standard flow did nothing, with no warning. Detection is unaffected — the monitor runs on its defaults regardless — so this only ever blocked tuning. But an operator raising the warn threshold to cut noise, or setting DISABLED to turn the monitor off, saw no change and no error and would reasonably conclude the knob was broken. Mapped with the same `${VAR:-}` shape as the DB_POOL_HEALTH_* block directly above, in both docker-compose.yml and deploy/docker-compose.prod.yml. Verified with `docker compose config` against an .env setting all three: before, the rendered api service has no EVENT_LOOP keys at all; after, it carries INTERVAL_MS=2000, STARVATION_WARN_MS=5000 and DISABLED=1. Confirmed separately for both compose files. Note on why the existing guard missed this: envComposeParity.test.ts extracts `.env.example` names with `/^([A-Z][A-Z0-9_]*)=/`, which matches uncommented assignments only. These three are documented as commented-out lines showing their defaults — the idiomatic way this repo documents optional knobs — so the parity check never considered them. Filed separately; not fixed here, because closing that gap needs a map-or-allowlist decision on each of the ~39 other commented-only variables it would surface.
Collaborator
Author
|
The Trivy Filesystem Scan red here is not from this PR — its diff is two YAML files and touches no lockfile or manifest. The blocking step reports 3 HIGH findings that arrived with a vulnerability-DB update: Fixed in #3240, which I verified locally against the CI-pinned Trivy: control tree exits 1 with the same 3 findings, that branch exits 0. This PR should go green once #3240 lands and it is rebased. |
ToddHebebrand
added a commit
that referenced
this pull request
Aug 8, 2026
…oS CVEs (#3241) Unblocks the PR queue. Trivy's vulnerability DB refreshed on 2026-08-08 and three new HIGH findings began failing **`Trivy Filesystem Scan` on every PR resolved after the refresh** — currently #3235 and #3238. **This is not caused by any of those PRs.** #3232 was scanned *before* the refresh and passed, which makes the failure look selective; it isn't, and it will redden `main` on the next push regardless of what gets merged. Exact repeat of the CVE-2026-59870 (js-yaml) episode in the previous release round. ## The three findings, and why they're handled differently | CVE | Package | Fix available? | Ships to users? | Action | |---|---|---|---|---| | CVE-2026-67213 | `nanoid` 3.3.16 | **Yes** — 3.3.17 / 5.1.6 | **Yes** — runtime dep of apps/mobile | pnpm override | | CVE-2025-71329 | `image-size` 1.2.1 | **No** | No — build-time only | `.trivyignore` | | CVE-2025-71330 | `image-size` 1.2.1 | **No** | No — build-time only | `.trivyignore` | ### nanoid — fixed properly Reached via `@react-navigation/native@7.3.8`, which is a **runtime** dependency of `apps/mobile`, so this one genuinely ships to devices. Override is upper-bounded `>=3.3.17 <4.0.0` so it stays a 3.3.16 → 3.3.17 patch bump rather than resolving to 6.x and dragging react-navigation through a major — the same bounding rationale used for the js-yaml override. The tree's other copies (5.1.16, 6.0.0) are already past the advisory's fixed versions and are untouched. **Lockfile diff is 2 lines**, `nanoid@3.3.16` removed: ``` $ grep -oE "nanoid@[0-9.]+" pnpm-lock.yaml | sort -u nanoid@3.3.17 nanoid@5.1.16 nanoid@6.0.0 ``` ### image-size — ignored, with justification There is **no fixed version upstream**. Trivy reports both as `affected` with an empty "Fixed Version" column, so no override or upgrade can close them today. Sole dependent is `metro@0.84.4` — the React Native bundler. Confirmed nothing else in the tree pulls it. metro runs on developer machines and in CI, never in a shipped image and never on a server or customer device. Both CVEs are DoS via a crafted image (a malformed ICNS for -71330) parsed by `image-size`; reaching that path means feeding a hostile image to our own bundler during our own build, i.e. the attacker already controls the source tree. The `.trivyignore` entry records the dependent, the non-exploitability argument, and explicit removal criteria — matching the justification standard the file already sets for its existing `node-ip` and pnpm blocks. **All 9 pre-existing entries are preserved**; this appends 2. ## Release note Worth a line in the v0.104.0 notes alongside the js-yaml entry: nanoid is a real (if low-severity) fix that reaches the mobile app; image-size is a documented, non-shipping accept. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Todd Hebebrand <todd@lanternops.io> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3236.
All three vars are documented as working knobs in
apps/docs/src/content/docs/deploy/environment.mdx:207-209and read atapps/api/src/services/eventLoopMonitor.ts(:71,:210,:497), but appeared in neither compose file's apienvironment:block. Compose only interpolates what is listed there, so setting them in.envwas a silent no-op.Mapped with the same
${VAR:-}shape as theDB_POOL_HEALTH_*block directly above them, in bothdocker-compose.ymlanddeploy/docker-compose.prod.yml.Verified end-to-end, not just eyeballed
docker compose configagainst an.envthat sets all three, rendering the api service:docker-compose.ymldeploy/docker-compose.prod.yml{}{}INTERVAL_MS=2000,STARVATION_WARN_MS=5000,DISABLED=1vitest run src/config/— 8 files, 303 tests, all passing (includesenvComposeParityandcomposeBindMounts).One correction to the issue
The issue says the vars are documented in "
.env.example/deploy/.env.example". Only the root.env.exampledocuments them (lines 452-454);deploy/.env.examplehas noEVENT_LOOPreferences at all. I did not add them there, becauseDB_POOL_HEALTH_*sets the precedent in the other direction — mapped indeploy/docker-compose.prod.yml, absent fromdeploy/.env.example. Happy to add a doc block to the droplet env example if you'd rather have parity there.Why the parity guard didn't catch this
Worth flagging, because it is the actual root cause and it is not specific to these three vars.
apps/api/src/config/envComposeParity.test.tsbuilds its list of documented variables with:The EVENT_LOOP vars are documented the way this repo documents optional knobs — commented out, showing the default:
So the guard never considered them. That is a structural blind spot aimed squarely at the class of variable most likely to be forgotten: optional tuning knobs nobody sets on day one.
DB_POOL_HEALTH_*is commented out too and only got wired because #3224 did it by hand.Sweeping both pairs for commented-only vars that reach no container: 34 in the root pair, 5 in the droplet pair. Not all are bugs — several are legitimately host-level or web build-time — but each needs a map-or-allowlist decision, which is why I have not folded that into this PR. Filed as #3239 with the full list and the two policy questions it raises.