Dentolize · Layered Sandbox Settings Walkthrough
On this pageBusiness viewTechnical view

The sandbox GitHub Environment

Business view

GitHub repos have a feature called "Environments" — named buckets of variables and secrets that a workflow job can opt into. This PR has the PR sandbox deploy opt into one called sandbox. That's the mechanism that makes "team-wide defaults" possible at all: it's simply where those defaults now live, editable by whoever administers the repo, without touching the workflow file or any individual PR. The one side effect worth knowing about: GitHub records every job that declares an environment as a "deployment" against it, so this PR's sandboxes will now show a sandbox deployment marker on the PR. That marker is informational only — see below for why it can't accidentally block anything.

Technical view

Source: .github/workflows/sandbox.yml:86-97.

deploy:
  needs: gate
  if: github.event.action != 'closed' && needs.gate.outputs.deploy == 'true'
  runs-on: [self-hosted, homelab, dentolize]
  timeout-minutes: 30
  # `sandbox` environment: team-managed base config (variables + secrets) for
  # sandboxes, layered UNDER each PR's own inline block. Declaring it here makes
  # those vars/secrets visible to the compose step. The environment has no
  # protection rules, so this does NOT gate PR deploys (it only records a
  # cosmetic `sandbox` deployment marker on the PR).
  environment: sandbox

.github/workflows/sandbox.yml:86-96

Why declaring it is necessary, not cosmetic

In GitHub Actions, an environment's variables and secrets are scoped to jobs that explicitly declare environment: <name> — a job that doesn't declare it cannot read them via vars/secrets, even if the environment exists and has values configured. Before this PR, the deploy job had no environment: key, so a SANDBOX_ALL_WHATSAPP variable or secret set on the sandbox environment would have been completely invisible to toJSON(vars)/toJSON(secrets) — the layering feature described in The precedence chain would have had nothing to read from that source. This one-line addition is what turns "team-wide defaults" from a wish into something the job can actually see.

Why it doesn't gate anything

Declaring environment: sandbox is also how GitHub environments implement protection rules — required reviewers, wait timers, branch restrictions — which would pause a job until satisfied. The sandbox environment has none configured, so the job proceeds immediately, same as before this PR; the existing gate job (sandbox.yml:50-84, unchanged by this PR) remains the only thing that decides whether a deploy runs at all, based on whether the PR-body ## 🧪 Sandbox block changed on an edited event. The tradeoff is explicit: if someone later adds a protection rule to the sandbox environment (e.g. "require a reviewer"), every PR sandbox deploy would start blocking on that approval — worth flagging to whoever administers environment settings, and worth a periodic check (see For Stakeholders).

The deployment marker

Because environment: sandbox is declared, GitHub Actions records each run of this job as a deployment to the sandbox environment, visible in the repo's Deployments and on the PR's timeline. This is purely a GitHub bookkeeping side effect of declaring the environment — the workflow doesn't create it explicitly, and nothing in sandbox.yml reads or reacts to it.

Unaffected by this change

The GITHUB_TOKEN used by the "Deploy sandbox" step (sandbox.yml:196) is the default, automatically-scoped workflow token — not something sourced from the sandbox environment's secrets. Declaring environment: sandbox doesn't change how that token is issued or scoped, and (per Secrets and safety guardrails) it's explicitly excluded from what a secret:<NAME> reference can resolve to.