Appearance
Credentials and access
For: the moment a command asks for a key and you need to know which one, where it comes from, and where it is meant to live.
No value appears on this page, and none should ever be added to it. Every row names a credential and says where to obtain it. If you find yourself pasting a secret into any documentation file, stop: the place for a value is the store the row names.
The accounts behind everything
Five accounts hold everything this product needs. Each is reached at its own console.
| Account | Console | Holds |
|---|---|---|
| Cloudflare | dash.cloudflare.com | the Workers, the Durable Object, the domain and its DNS |
| Forgejo | forge.tailc53a08.ts.net | the repository, its issues, its pull requests and continuous integration |
| Expo | expo.dev | the mobile project, its build profiles and its over-the-air channels |
| Apple Developer | developer.apple.com and appstoreconnect.apple.com | the iOS signing identity and App Store listing |
| Google Play | play.google.com/console | the Android signing key and Play listing |
Deploying to Cloudflare
Two values authenticate every deploy and every wrangler command. Both are read from your environment, or from the repository's gitignored .env file.
| Name | Where to get it | Which job wants it |
|---|---|---|
CLOUDFLARE_API_TOKEN | Cloudflare dashboard → My Profile → API Tokens → Create Token, choosing "Edit Cloudflare Workers", which covers deploys. | every deploy, every wrangler command |
CLOUDFLARE_ACCOUNT_ID | Cloudflare dashboard → Workers & Pages → Overview, right-hand column | every deploy |
CLOUDFLARE_ZONE_ID | Cloudflare dashboard → Websites → the domain → Overview, right-hand column | production deploys only, and only when overriding the built-in zone |
The token is the one that matters. Scope it to Workers rather than to the whole account, and rotate it from the same page if it ever reaches a log or a screenshot.
Both deploy scripts exit with code 2 when either of the first two is missing, so a missing credential is named rather than guessed at.
To rehearse a deploy without any credential at all, run the dry form:
bash
GW_DEPLOY_DRY=1 npm run deploy:stagingSecrets held by a deployed worker
These live in Cloudflare, attached to one worker, and never in the repository.
| Name | Set with | Notes |
|---|---|---|
ADMIN_EMAIL | npx wrangler secret put ADMIN_EMAIL --name <worker> | a worker without it refuses every request |
ADMIN_CLAIM_HASH | set by the deploy from your local owner token | a 64-character hex digest when overridden by hand |
RESET_TOKEN | set by the staging deploy from GW_STAGING_RESET | staging only; production has no reset |
Each worker holds its own copies. The two worker names are grafted-wars-true-staging for staging and grafted-wars-staging for production, and they read as the reverse of what they are.
An ordinary deploy preserves an existing secret. It is lost only if the worker is deleted and recreated, after which the universe refuses every request until it is put back.
Being owner on a deployment
Owner is claimed per deployment, from a token minted on your machine.
| Item | Where it lives | How to get it |
|---|---|---|
| owner token | ~/.grafted-wars/owner-token on your machine | node scripts/owner-claim.mjs mint |
| claim-link page | ~/rocket-showroom/grafted-wars-enter.html | node scripts/owner-claim.mjs page <base url> |
| owner session | your browser, per deployment | open the claim page and follow its link once |
The token is the root of this. Losing it means minting a new one and redeploying, because the deployed worker checks a claim against the hash of the token that was present at deploy time.
The Forge
Continuous integration and the tracker tools authenticate against the Forge.
| Name | Where it comes from | Notes |
|---|---|---|
| git credential | your operating system's credential store, for the Forge remote's host | the ordinary route; nothing to configure once you have pushed once |
FORGE_TOKEN | Forgejo → Settings → Applications → Generate Token | read only when the credential store has no entry |
REVIEW_GATE_TOKEN | a Forgejo user token, registered as a repository secret | lets the review gate read collaborator permissions |
GITHUB_TOKEN | supplied to each workflow run automatically | nothing to set |
A request to a host that is neither the git remote's host nor the configured Forge base carries no credential at all, by construction. Such a request reads back as a 404 rather than an authentication failure.
Mobile
The mobile project is an Expo application, and its build credentials are held by Expo rather than by this repository.
| Item | Value or source | Notes |
|---|---|---|
| Expo account | evgeniiarts | the owner recorded in the app configuration |
| EAS project | recorded in platforms/mobile/app.config.ts | the project identifier the builds attach to |
| bundle identifier and package | com.graftedwars.game | the same string on both platforms |
| Expo access token | expo.dev → Account Settings → Access Tokens | needed for non-interactive builds |
Signing material is generated and stored by Expo when you first build, and you are prompted for it then.
| Platform | Credential | Where it comes from |
|---|---|---|
| iOS | Apple Developer Program membership, a distribution certificate and a provisioning profile | developer.apple.com; Expo can generate and manage both |
| iOS | App Store Connect API key, for automated submission | appstoreconnect.apple.com → Users and Access → Integrations |
| Android | an upload keystore | generated by Expo on first build, or supplied by you |
| Android | a Google Play service account JSON key | Google Cloud console, granted access in the Play Console |
Store none of these in this repository. Expo holds the signing material, and the Play service account key belongs wherever you keep private keys.
Runtime configuration the mobile app reads
These are settings rather than secrets, and they change which server the shell points at.
| Name | Effect | Default |
|---|---|---|
GRAFTED_WARS_GAME_URL | the server the shell loads | https://grafted-wars.com |
GRAFTED_WARS_ALLOW_HTTP_LOCALHOST | permits a plain-HTTP localhost target when set to true | off |
GRAFTED_WARS_SUPPORT_EMAIL | the support address shown in the app | unset, and the entry is hidden |
The URL is validated rather than trusted. A value carrying embedded credentials is discarded, and a plain-HTTP value is discarded unless it is localhost and the override above is on.
Where these belong
| Store | What goes there |
|---|---|
your environment, or the gitignored .env | Cloudflare token and account id |
| Cloudflare, per worker | ADMIN_EMAIL and the other worker secrets |
your machine, at ~/.grafted-wars | the owner token |
| your operating system's credential store | the Forge git credential |
| Expo | mobile signing material |
| the repository | none of the above |
A minted test-account store also holds live credentials. It is gitignored, and it belongs in no commit and on no ticket.
If one leaks
Rotate at the source rather than trying to scrub the history. A Cloudflare token is revoked and reissued from the same page it was created on. A Forge token is revoked in Forgejo's application settings. An owner token is re-minted and the deployment redeployed. Mobile signing material is rotated through Expo and the relevant store console.