Security & guardrails
Business view
This mechanism lets people inject configuration — including secrets like Meta/WhatsApp API credentials — into a shared demo environment. Three things keep that safe:
- Scoping is explicit and prefix-based. A setting only applies if its name starts with
SANDBOX_ALL_orSANDBOX_<BRANCH>_. Nothing else in thesandboxEnvironment (or the repo/org variables GitHub also happens to expose to the job) is picked up, even though the underlying GitHub Actions APIs technically expose everything. - The one token that must never leave the runner —
github_token, the workflow's own repo-write credential — physically cannot be selected, because it isn't prefixed withSANDBOX_...and the compose step only ever reads prefixed keys. - Nothing sensitive is echoed to the job log. The step logs which toggles are set and which env variable names were injected, never values — secret or otherwise.
This reuses a settings format the team already trusts (the PR-body block has worked the same way for regular PR sandboxes), so there's no new class of behavior to review — just a new place the same shape of data can come from.
Technical view
Why the prefix requirement exists
toJSON(vars) and toJSON(secrets) in a GitHub Actions job return every variable/secret visible to that job — repository-level, organization-level, and (once environment: sandbox is declared) environment-level, all flattened into one object with no indication of origin. The PR description calls this out explicitly: "The prefix is required because toJSON(vars) also merges repo-level variables; it scopes precisely." Without the SANDBOX_ALL_/SANDBOX_<REF>_ filter (sandbox-ops.yml:88-90), any repo variable unrelated to sandboxes would silently become an env override or, worse, collide with a reserved toggle name.
github_token can't leak — by construction, not by check
Unlike the PR-body path (sandbox.yml:140), which explicitly checks for and rejects a secret:github_token reference with error("github_token cannot be injected into a sandbox"), this path has no such check — and doesn't need one. github.token is a job-scoped ephemeral credential auto-injected by Actions; it is never a member of the secrets context object that toJSON(secrets) serializes, and it certainly isn't named SANDBOX_ALL_GITHUB_TOKEN or SANDBOX_MAIN_GITHUB_TOKEN. There is no code path in sandbox-ops.yml:73-98 by which it could reach merged. This is a structural guarantee, not a runtime guard — worth knowing if this logic is ever refactored, since the safety currently comes from "it was never in the input," not from an explicit denylist entry the way the PR-body path does it.
Secrets override variables, deliberately
sandbox-ops.yml:86 iterates (vars_, secrets_) in that fixed order, so a secret always overwrites a variable of the same post-prefix key in merged. This lets a team member start with a plain variable (e.g. SANDBOX_MAIN_WHATSAPP=true, visible in the Environment UI, fine to be public) and later add a secret under the same key to override it with a masked value if the value itself needs to stay hidden — without having to first delete the variable.
Log hygiene
sandbox-ops.yml:99-108 deliberately logs toggles (the non-env keys of the composed settings — booleans and the seed mode, nothing secret-shaped) and env.keys() — never env.values(). Contrast with the PR-body path (sandbox.yml:123-125), which logs the settings block before secret references are resolved, for the same reason: by the time either code path has a resolved secret value in hand, that value is not written to a log stream. GitHub Actions would mask a genuine secrets.* value automatically if it did leak into a log line, but a plain variable value has no such automatic masking — so both code paths are conservative about what they print regardless of whether the value happens to be secret or not.
Test coverage claimed in the PR
The PR description states the compose logic is unit-tested for: main-scoped vars applying, other-branch vars not leaking into main, github_token/unprefixed vars being excluded, secret overriding variable, and an empty result correctly producing {} (i.e., falling through to CLI defaults). Those tests live outside this repository (as part of the sandbox CLI / homelab tooling, not packages/*), so they aren't visible from /work/repo — this doc records the claim as stated in the PR description rather than verifying the test file directly. See For Quality for what to independently re-check.
Scope of what can actually be injected
Because the env map (whatever survives the toggle/seed split) is injected wholesale into server / queue / cron / whatsapp containers by the sandbox CLI, anyone with write access to the sandbox GitHub Environment can set arbitrary environment variables on those containers for main (or any other targeted branch). That's the same trust boundary the PR-body env: block already has (sandbox.yml:126-148 — "an injected secret is readable by anyone with this sandbox's access cred... prefer test/dev creds, not production secrets"). This PR does not change that boundary; it opens a second door into the same room.