Dentolize ยท Layered Sandbox Settings Walkthrough
On this pageThe one-page version๐Ÿงช SandboxPrecedence, lowest to highestWhat did not change

Layered Sandbox Settings

PR #427 โ€” ci(sandbox): layer sandbox settings โ€” env vars โ†’ secrets โ†’ PR inline Status: unreleased. This changes one file โ€” .github/workflows/sandbox.yml โ€” in the Dentolize CI pipeline. It does not touch the dental-clinic product (server, clinic-web, clinic-mobile, patient-web, prisma). Nobody using Dentolize as a clinic will ever see this change; it changes how engineers get their PR preview environments configured.

The one-page version

Every open pull request in this repo gets an automatic preview deployment โ€” a "sandbox" โ€” at <branch>.sandbox.anastawfik.com. A PR author can steer that sandbox with a fenced settings block in the PR description:

~~~

๐Ÿงช Sandbox

whatsapp: true
env:
  SOME_FLAG: "1"

~~~

Before this PR, that PR-body block was the only input the deploy job could see. Team-wide defaults โ€” "every sandbox should run with cron: true by default", or "here's a shared test API key every sandbox can use" โ€” had no home. They had to be either hard-coded into the workflow, or copy-pasted into every single PR description by hand.

This PR gives those defaults a home: the sandbox GitHub Environment, which stores team-managed variables and secrets. The deploy job now reads that environment as a base layer, and the PR's own inline block still overrides it, key by key.

Precedence, lowest to highest

built-in compose defaults
  โ†’ SANDBOX_ALL_* variables
  โ†’ SANDBOX_ALL_* secrets
  โ†’ SANDBOX_<branch>_* variables
  โ†’ SANDBOX_<branch>_* secrets
  โ†’ PR-body ## ๐Ÿงช Sandbox block   (always wins)

Later always overrides earlier, key by key โ€” not block by block. A PR can override a single setting without having to repeat everything else the team already configured.

What did not change

  • The sandbox CLI on the runner is unchanged. The workflow still emits

the same JSON shape (env, whatsapp, two_regions, cron, queue, seed) that the CLI's load_settings already reads.

  • The PR-body block's syntax is unchanged. Existing PR descriptions with

a ## ๐Ÿงช Sandbox block keep working exactly as before, and still win every conflict.

  • **The secret:<NAME> resolution and the github_token guardrail are

preserved** โ€” a PR can still reference a real secret by name without ever printing its value, and github_token still can't be injected.

  • No new deploy gate. The sandbox GitHub Environment has no protection

rules, so declaring it doesn't add an approval step โ€” see The sandbox GitHub Environment for what it does add.

See The precedence chain and Secrets and safety guardrails for exactly how the layering and the secret handling work, file:line into .github/workflows/sandbox.yml.