Environment manifest
Field-by-field reference for .greenroom/environment.json.
The environment manifest is your attestation of what environment Greenroom's virtual user is allowed to touch. It lives at .greenroom/environment.json, is validated strictly (unknown fields are rejected), and is always read from the PR's base revision, so a pull request cannot change its own policy.
Fields
| Field | Type | Required | Meaning |
|---|---|---|---|
schemaVersion | "1.0" | yes | Schema version, currently the literal "1.0". |
classification | "preview" | "staging" | "test" | yes | What kind of environment this is. |
isolated | true | yes | Your attestation that this environment holds no production data. The literal true is required; there is no way to run against a non-isolated environment. |
resetStrategy | "fresh_install" | "test_hook" | "ephemeral_deployment" | yes | How the app returns to a known state between walks. iOS requires "fresh_install". |
networkControl | "playwright" | "external_proxy" | "sandboxed_backend" | yes | How network egress is governed. Web requires "playwright". iOS accepts "external_proxy" or "sandboxed_backend". |
allowedHosts | string[], 1 to 50 entries | yes | Every host the app may reach during a walk. Include font CDNs, analytics, and crash reporters. |
productionHosts | string[], up to 50 entries | no (default []) | Hosts that are production. Declaring them lets Greenroom prove the walk never touched one. |
sandboxPurchases | boolean | no (default false) | Whether purchase flows run against a sandbox (StoreKit test configuration, Stripe test mode). |
notes | string, up to 1000 chars | no | Free-form context for reviewers of the manifest. |
auth | object | no (default { "mechanism": "signed_out" }) | How a walk that starts behind a sign-in wall gets its session: signed_out, or session_import with the secret name, the storage target and reset. iOS only. The contract is in testing authenticated apps. |
Validation rules that bite
- A host may not appear in both
allowedHostsandproductionHosts. The comparison is case-insensitive and the manifest is rejected outright, because an allowlisted production host would mean the virtual user can reach real customer data. - The platform constrains
networkControl. Web runs must declareplaywright(the browser enforces the allowlist in-line). iOS runs must declareexternal_proxyorsandboxed_backend;playwrightis meaningless there and rejected. - iOS requires
resetStrategy: "fresh_install". Each walk starts from a clean install on a dedicated simulator. - An incomplete allowlist ends walks, correctly. Any request to an unlisted host is contained and the walk ends with the violation recorded. The fix is completing the allowlist, not relaxing policy: watch your app's first run and add what it legitimately needs.
Third-party SDKs and public keys in the test build
A third-party SDK the test build leaves unconfigured (no key) usually makes no requests; list its host under productionHosts so the walk proves it stayed silent. One configured with a production key contacts its host and must be either allowlisted with a test project or left unconfigured.
Some SDKs will not let the app start without a key (RevenueCat's configure throws, and the startup chain after it never runs). The test build then needs a test project's public SDK key, exported in the workflow's prepare block through a GitHub Actions variable (export REVENUECAT_API_KEY_IOS=${{ vars.REVENUECAT_TEST_PUBLIC_KEY }}), with the SDK's host in allowedHosts. Public SDK keys are the ones the vendor designs to ship inside the app binary (RevenueCat public keys, PostHog project tokens, Stripe publishable keys); they are allowed in prepare. A private key, secret, service-role or signing key never is: prepare runs with no credentials, cannot read repository secrets, and is readable by anyone with the repository. The setup check refuses a value that looks like a credential and any secrets reference in prepare.
Sentry: the ingest host is only knowable from the DSN. A test build compiled without a DSN sends nothing, so list no Sentry host; only when the test build carries a DSN, list its exact host.
Choosing networkControl for iOS
sandboxed_backend means your simulator build is compiled against a test or staging backend, so it cannot reach production by construction. Greenroom does not intercept or record simulator traffic; the guarantee is the build configuration. This is the recommended path: it requires no infrastructure beyond the build configuration you likely already have.
external_proxy means an egress proxy or firewall on the CI host denies everything outside allowedHosts in-line. It is the strictest option, for teams that already operate one.