| 1 | --- |
| 2 | title: Secrets and variables |
| 3 | description: One list of keys and values for workflows and deployments. Each row says which environments it applies to and who reads it. |
| 4 | --- |
| 5 | |
| 6 | A [project](/guides/projects/) and a workspace each have one list of |
| 7 | secrets and variables. |
| 8 | Workflows and deployments both read from it; each row says whether one, |
| 9 | the other or both do, and which environments it applies to. |
| 10 | |
| 11 | | Where | Page | Who sees and changes it | |
| 12 | | --- | --- | --- | |
| 13 | | A project | **Settings → Secrets and variables**, `g1t.sh/<workspace>/<project>/settings/secrets` | People with the Admin [role](/guides/access-and-roles/) on its repository | |
| 14 | | A workspace | **Settings → Secrets and variables**, `g1t.sh/<workspace>/-/secrets` | Owners | |
| 15 | |
| 16 | Seeing the list needs the same as changing it: a project's rows, config |
| 17 | values included, are for Admins of its repository, and the page is not |
| 18 | shown to anyone else. |
| 19 | |
| 20 | ## A row |
| 21 | |
| 22 | | Field | | |
| 23 | | --- | --- | |
| 24 | | **Type** | **Secret**: sealed when saved and never shown again, hidden in logs. For passwords, API keys and tokens. **Config**: readable by whoever may see the list. For values that are not sensitive. Config can be changed to a secret; a secret can never become config. | |
| 25 | | **Key** | Letters, digits and underscores, not starting with a digit, upper-cased: `STRIPE_KEY`. Keys starting with `G1T_` or `GITHUB_` are g1t's own. | |
| 26 | | **Value** | Up to 48 KB. | |
| 27 | | **Note** | Optional: where to rotate it, or who to ask. | |
| 28 | | **Environments** | **All environments**, or only some: **Production**, **Preview**, or any name a workflow job uses in `environment:`, such as `staging`. | |
| 29 | | **Available to** | **Workflows**, **Deployments**, or both (the default). | |
| 30 | | **Projects** | A workspace's row only: every project, or the ones you choose. | |
| 31 | |
| 32 | ### A value per environment |
| 33 | |
| 34 | A key can have one row per environment, so production and previews use |
| 35 | different values. For example, Stripe's live key in production and its |
| 36 | test key everywhere else: |
| 37 | |
| 38 | | Key | Type | Environments | Value | |
| 39 | | --- | --- | --- | --- | |
| 40 | | `STRIPE_KEY` | Secret | Production | `sk_live_…` | |
| 41 | | `STRIPE_KEY` | Secret | Preview | `sk_test_…` | |
| 42 | |
| 43 | Two rows of the same key and type cannot apply to the same environment. |
| 44 | A key can also have a row for all environments alongside rows for some: |
| 45 | the rows for some win where they apply. |
| 46 | |
| 47 | ### Adding many at once |
| 48 | |
| 49 | Paste the contents of a `.env` file into **Key** when adding. Each |
| 50 | `KEY=value` line becomes a row with the type, environments and readers you |
| 51 | choose; blank lines and `#` comments are skipped. |
| 52 | |
| 53 | ## Who reads what |
| 54 | |
| 55 | | Reader | Reads | Environment it asks for | |
| 56 | | --- | --- | --- | |
| 57 | | A workflow job | Rows available to Workflows: secrets as `${{ secrets.KEY }}`, config as `${{ vars.KEY }}` | The job's `environment:`, if it has one | |
| 58 | | A deploy build | Rows available to Deployments, as environment variables | `production` or `preview` | |
| 59 | | A running app | The same rows, as bindings: `env.KEY` (a secret as a secret binding) | `production` or `preview` | |
| 60 | | An agent, the merge queue's builds | Nothing | | |
| 61 | |
| 62 | For each key, a reader gets the row for its environment if there is one, |
| 63 | else the row for all environments. A row only for other environments gives |
| 64 | it nothing. |
| 65 | |
| 66 | A project's row overrides its workspace's of the same key. The project's |
| 67 | list shows the workspace's rows that reach it, marked |
| 68 | **Workspace**, until it sets the key itself. |
| 69 | |
| 70 | A running app's rows are bound by g1t when it puts the app up; they never |
| 71 | pass through the build's sandbox. A row of a Workers project's own |
| 72 | `vars` with the same name is replaced. |
| 73 | |
| 74 | ## Who gets secrets |
| 75 | |
| 76 | Secrets go only to trusted runs: |
| 77 | |
| 78 | - pushes, schedules, manual runs and the merge queue; |
| 79 | - pull requests whose author has the Write [role](/guides/access-and-roles/) |
| 80 | or higher on the repository, a member or an |
| 81 | [outside collaborator](/guides/access-and-roles/#outside-collaborators). |
| 82 | For one g1t made, that is whoever asked for it; |
| 83 | - pull requests g1t opened on its own, such as a security update. |
| 84 | |
| 85 | Anyone else's pull request, such as one from a fork or by someone with |
| 86 | Read or Triage (who may open one on a private repository too), runs its |
| 87 | workflows, and builds its preview, with config only: no secrets, and a |
| 88 | `G1T_TOKEN` that can only read. Its runs may first wait for someone with |
| 89 | Write to [approve them](/guides/actions/#pull-requests-from-outside). |
| 90 | |
| 91 | A job that names an environment gets that environment's secrets only once |
| 92 | the environment's [protection rules](/guides/actions/#environments) let it |
| 93 | through: required reviewers, a wait timer, and which branches may deploy. |
| 94 | |
| 95 | ## G1T_TOKEN |
| 96 | |
| 97 | Every workflow job gets `${{ secrets.G1T_TOKEN }}`: a token for that job |
| 98 | alone, which reaches its repository only, can do what the job's |
| 99 | `permissions:` say, and stops working when the job ends. |
| 100 | `${{ secrets.GITHUB_TOKEN }}` and `${{ github.token }}` are the same token, |
| 101 | so workflows written for GitHub work unchanged. See |
| 102 | [the job's token](/guides/actions/#the-jobs-token). |
| 103 | |
| 104 | ```yaml |
| 105 | # On the job: permissions: { issues: write } |
| 106 | - name: Open an issue when the nightly build fails |
| 107 | if: failure() |
| 108 | run: | |
| 109 | curl -X POST https://api.g1t.sh/repos/${{ github.repository }}/issues \ |
| 110 | -H "Authorization: Bearer ${{ secrets.G1T_TOKEN }}" \ |
| 111 | -d '{"title":"Nightly build failed"}' |
| 112 | ``` |
| 113 | |
| 114 | `G1T_TOKEN` can neither list nor change secrets or variables, so a |
| 115 | workflow cannot read or rewrite what it runs with. No workspace access |
| 116 | token can change them either: use a person's token, or the site. |
| 117 | |
| 118 | ## From the API |
| 119 | |
| 120 | The routes are GitHub's, and calls written for GitHub work unchanged: a |
| 121 | key named without an `id` or `environments` is the key's row for all |
| 122 | environments. |
| 123 | |
| 124 | | MCP (`secret` tool) | Route | |
| 125 | | --- | --- | |
| 126 | | `list_secrets` | `GET /repos/{owner}/{repo}/actions/secrets` | |
| 127 | | `set_secret` | `PUT /repos/{owner}/{repo}/actions/secrets/{key}` | |
| 128 | | `delete_secret` | `DELETE /repos/{owner}/{repo}/actions/secrets/{key}` | |
| 129 | | `list_variables` | `GET /repos/{owner}/{repo}/actions/variables` | |
| 130 | | `set_variable` | `POST /repos/{owner}/{repo}/actions/variables`, `PATCH …/variables/{key}` | |
| 131 | | `delete_variable` | `DELETE /repos/{owner}/{repo}/actions/variables/{key}` | |
| 132 | |
| 133 | A workspace's are under `/workspaces/{workspace}/actions/secrets` and |
| 134 | `…/variables`. Beyond GitHub's fields, a row takes: |
| 135 | |
| 136 | | Field | | |
| 137 | | --- | --- | |
| 138 | | `id` | The row to change or remove, from a list. | |
| 139 | | `available_to` | `["workflows"]`, `["deployments"]` or both. `availableTo` works too. | |
| 140 | | `environments` | `["production"]`, `["preview", "staging"]`; `[]` for all. | |
| 141 | | `projects` | A workspace's row: project names; `[]` for every one. (`repositories` is read the same way.) | |
| 142 | | `note` | Where to rotate it, or who to ask. | |
| 143 | |
| 144 | ```sh |
| 145 | curl -X PUT https://api.g1t.sh/repos/acme/web/actions/secrets/STRIPE_KEY \ |
| 146 | -H "Authorization: Bearer $YOUR_TOKEN" \ |
| 147 | -d '{"value":"sk_live_…","environments":["production"],"available_to":["deployments"]}' |
| 148 | ``` |
| 149 | |
| 150 | A secret is sent as plain `value` over HTTPS, not encrypted to a public |
| 151 | key first. |