Skip to content

fix(deploy): stop MAPLE_ENVIRONMENT being overridable by a stray env var - #284

Merged
Makisuo merged 1 commit into
mainfrom
fix/maple-environment-hardening
Jul 30, 2026
Merged

fix(deploy): stop MAPLE_ENVIRONMENT being overridable by a stray env var#284
Makisuo merged 1 commit into
mainfrom
fix/maple-environment-hardening

Conversation

@Makisuo

@Makisuo Makisuo commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

The bug

Both email-capable workers passed MAPLE_ENVIRONMENT through optionalPlain:

const optionalPlain = (key: string, fallback?: string) => {
    const value = process.env[key]?.trim() || fallback   // ← process.env wins
    return value ? { [key]: value } : {}
}

So optionalPlain("MAPLE_ENVIRONMENT", resolveDeploymentEnvironment(stage)) doesn't mean "use the stage" — it means "use process.env if present, otherwise the stage." The stage-derived value is the fallback, not the source of truth.

Why it matters

Both non-production email gates derive from that one variable:

  • apps/alerting/src/worker.ts — the scheduled() early return that skips all crons off production
  • apps/api/src/lib/EmailService.tsemailAllowed, which isConfigured depends on

A stray MAPLE_ENVIRONMENT=production reaching a pr-N or stg deploy environment opens both at once. Preview and staging stages run the same digest and onboarding crons against branched databases that still hold real Clerk members, so at that point the only remaining guard is the absence of the prd-only EMAIL binding — one config line away from a duplicate mailing to real users.

The fix

Derive it from the stage, non-overridable, in both workers. The prd-only binding gating stays as defence in depth; it's just no longer load-bearing on its own.

chat-flue and electric-sync use the same optionalPlain pattern but have no EMAIL binding and no email gate, so they're left alone — worth a follow-up only if consistency is wanted for its own sake.

Provenance

Found while designing non-prod containment for a third-party email vendor, which needed an equivalent guard and had no Cloudflare binding to lean on. That vendor work has been dropped — onboarding will instead move to a Cloudflare Workflow with durable step.sleep, since the machinery is largely already there. This bug predates that whole exercise and stands on its own.

Verification

Config-only change, no runtime code touched. tsc --noEmit clean on apps/api and apps/alerting.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Both workers passed MAPLE_ENVIRONMENT through `optionalPlain`, which resolves to
`process.env[key]?.trim() || fallback` — so process.env WINS over the
stage-derived value it was meant to fall back to.

That matters because both non-production email gates derive from this single
variable: the alerting worker's scheduled() early return, and
EmailService.emailAllowed. A stray MAPLE_ENVIRONMENT=production reaching a pr-N
or stg deploy environment opens both at once, and preview stages run the same
digest and onboarding crons against branched DBs holding real Clerk members —
so the only thing left standing between a preview worker and a duplicate mailing
to real users is the absence of the prd-only EMAIL binding.

Deriving it from the stage removes the override. The binding gating stays as
defence in depth; this just means it is no longer load-bearing on its own.

Found while designing containment for a third-party email vendor, which needed
an equivalent guard and had no binding to lean on. That work is dropped, but
this bug predates it and stands alone.
@pullfrog

pullfrog Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Your Pullfrog Router balance is exhausted.

You have a payment method on file but auto-reload is disabled, so runs paused once your balance went past the overdraft buffer.

Top up balance → · Enable auto-reload →

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Rerun failed job ➔View workflow run | via Pullfrog | Using Claude Opus𝕏

@Makisuo
Makisuo merged commit f52a4eb into main Jul 30, 2026
11 of 12 checks passed
@Makisuo
Makisuo deleted the fix/maple-environment-hardening branch July 30, 2026 21:07
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

🍁 Maple PR preview

Note

Preview resources were removed when this pull request closed.

Final commit 9ab7e72 · View workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant