fix(scripts): detect globalThis-cast and severity-threshold env reads#8632
Conversation
The selfhost-env-reference generator only recognized .env accesses whose
base is a bare process/c identifier, and helper calls carrying an env var
name in a single fixed argument slot. src/selfhost/posthog.ts reads
POSTHOG_SERVER_NAME through (globalThis as unknown as {...}).process?.env
and POSTHOG_MIN_SEVERITY/POSTHOG_REPO_MIN_SEVERITY as string-literal
arguments 2 and 3 of resolveSeverityThreshold(), so all three real
operator-facing vars were silently absent from the generated reference.
- isEnvContainer now accepts a .env base that resolves to
globalThis.process through casts (new isProcessExpression), not just a
bare process/c identifier.
- ENV_NAME_LITERAL_ARG_HELPERS entries now carry a list of argument
indexes, and resolveSeverityThreshold is registered at indexes 2 and 3.
- Regenerated apps/loopover-ui/src/lib/selfhost-env-reference.ts: adds
POSTHOG_MIN_SEVERITY, POSTHOG_REPO_MIN_SEVERITY, POSTHOG_SERVER_NAME
(src/selfhost/posthog.ts) plus PAGERDUTY_MIN_SEVERITY and
PAGERDUTY_REPO_MIN_SEVERITY (src/services/notify-pagerduty.ts:103,
the same resolveSeverityThreshold blind spot in an already-scanned
root, surfaced by the same generalized fix).
- Four new fixture tests (match + deliberate non-match for each new
branch) in test/unit/selfhost-env-reference-script.test.ts.
|
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 #8632 +/- ##
=======================================
Coverage 92.77% 92.77%
=======================================
Files 798 798
Lines 79464 79464
Branches 24078 24078
=======================================
Hits 73725 73725
Misses 4592 4592
Partials 1147 1147
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-25 16:13:49 UTC
Review summary Nits — 5 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
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://loopover.ai/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
The selfhost-env-reference generator's AST visitor only recognized
.envaccesses whose base is a bareprocess/cidentifier, plus helper calls carrying an env var name in one fixed argument slot.src/selfhost/posthog.ts(#8287) reads three real, operator-facing config vars through shapes outside that set, so all three were silently absent from the generated reference operators rely on:POSTHOG_SERVER_NAME(src/selfhost/posthog.ts:179) — read via(globalThis as unknown as { process?: { env?: ... } }).process?.env?.POSTHOG_SERVER_NAME. The base of.envis a property access on a cast expression, not an identifier, soisEnvContainernever matched it. This is the migration regression: the Sentry-era equivalent (env.SENTRY_SERVER_NAME) WAS detected and listed.POSTHOG_MIN_SEVERITY/POSTHOG_REPO_MIN_SEVERITY(src/selfhost/posthog.ts:81) — passed as string-literal arguments 2 and 3 toresolveSeverityThreshold(...), which readsenv[globalVarName]/env[repoMapVarName]internally via computed access that is AST-invisible at the read site. The helper was not inENV_NAME_LITERAL_ARG_HELPERS(pre-existing gap, per the issue).Changes
scripts/gen-selfhost-env-reference.tsisEnvContainernow delegates its.env-base check to a newisProcessExpression, which accepts (a) the existing bareprocess/cidentifiers and (b) a.processproperty access whose base resolves to theglobalThisidentifier after unwrapping parentheses andascasts (via the existingunwrapEnvExpression, so chainedas unknown as {...}casts work the same way they already did forenvitself, docs(selfhost): fill config/env doc gaps and reconcile checkRunDetailLevel default mismatch #2907). No var name is hardcoded — any future var read through the sameglobalThis-cast shape is caught, matching how selfhost-env-reference generator misses AI review-pipeline env vars #6993 generalized rather than special-cased.ENV_NAME_LITERAL_ARG_HELPERSentries now carry a list of argument indexes instead of a single index, andresolveSeverityThresholdis registered at indexes[2, 3]; the visitor adds every string-literal name argument present at a registered index.test/unit/selfhost-env-reference-script.test.ts— four new fixture tests (newdescribeblock for this issue): a fixture using the exact(globalThis as unknown as {...}).process?.env?.FOOshape fromposthog.ts:179asserting the var is returned throughcollectSelfHostEnvVars; a deliberate non-match with the same cast silhouette but a non-globalThisbase; a fixture using the exactresolveSeverityThreshold(env as unknown as Env, repo, "VAR_A", "VAR_B")call asserting both names are returned; and a deliberate non-match calling a same-arity helper outside the allowlist. None stubbed.apps/loopover-ui/src/lib/selfhost-env-reference.ts— regenerated vianpm run selfhost:env-referenceand committed in the same PR. The diff is additions only:POSTHOG_MIN_SEVERITY,POSTHOG_REPO_MIN_SEVERITY, andPOSTHOG_SERVER_NAME, each attributed tosrc/selfhost/posthog.ts.Note: two additional rows the generalized fix surfaces
The regenerated reference also gains
PAGERDUTY_MIN_SEVERITYandPAGERDUTY_REPO_MIN_SEVERITY, attributed tosrc/services/notify-pagerduty.ts— that file is already inDEFAULT_SOURCE_ROOTSand calls the sameresolveSeverityThreshold(env, repo, "PAGERDUTY_MIN_SEVERITY", "PAGERDUTY_REPO_MIN_SEVERITY", DEFAULT_MIN_SEVERITY)shape at line 103 (#5119). This is the identical pre-existing blind-spot instance the issue documents for the deleted Sentry-era vars: both are real, operator-facing severity knobs that were silently missing from the reference for the same reason. Excluding them would require exactly the file-scoped special-casing the issue forbids ("the fix must generalize the AST visitor's pattern recognition so any future var read the same way is also caught"), so they are included rather than gerrymandered out. Beyond these strictly-additive rows, nothing else in the generated output changes.Verification
npx vitest run test/unit/selfhost-env-reference-script.test.ts— 10 tests pass (6 existing + 4 new).npm run selfhost:env-referencere-run; output committed.npm run selfhost:env-reference -- --checkpasses clean against the committed output (the drift check CI runs intest:ci).npm run typecheckandnpm run ui:typecheckpass.git diff --checkclean.Closes #8627