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
sandboxCLI 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 thegithub_tokenguardrail 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
sandboxGitHub 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.