Skip to content

One list of keys and values for workflows and deployments. Each row says which environments it applies to and who reads it.

A project and a workspace each have one list of secrets and variables. Workflows and deployments both read from it; each row says whether one, the other or both do, and which environments it applies to.

Where Page Who sees and changes it
A project Settings → Secrets and variables, g1t.sh/<workspace>/<project>/settings/secrets People with the Admin role on its repository
A workspace Settings → Secrets and variables, g1t.sh/<workspace>/-/secrets Owners

Seeing the list needs the same as changing it: a project’s rows, config values included, are for Admins of its repository, and the page is not shown to anyone else.

Field
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.
Key Letters, digits and underscores, upper-cased: STRIPE_KEY. Keys starting with G1T_ or GITHUB_ are g1t’s own.
Value Up to 48 KB.
Note Optional: where to rotate it, or who to ask.
Environments All environments, or only some: Production, Preview, or any name a workflow job uses in environment:, such as staging.
Available to Workflows, Deployments, or both (the default).
Projects A workspace’s row only: every project, or the ones you choose.

A key can have one row per environment, so production and previews use different values. For example, Stripe’s live key in production and its test key everywhere else:

Key Type Environments Value
STRIPE_KEY Secret Production sk_live_…
STRIPE_KEY Secret Preview sk_test_…

Two rows of the same key and type cannot apply to the same environment. A key can also have a row for all environments alongside rows for some: the rows for some win where they apply.

Paste the contents of a .env file into Key when adding. Each KEY=value line becomes a row with the type, environments and readers you choose; blank lines and # comments are skipped.

Reader Reads Environment it asks for
A workflow job Rows available to Workflows: secrets as ${{ secrets.KEY }}, config as ${{ vars.KEY }} The job’s environment:, if it has one
A deploy build Rows available to Deployments, as environment variables production or preview
A running app The same rows, as bindings: env.KEY (a secret as a secret binding) production or preview
An agent, acceptance checks, the merge queue Nothing

For each key, a reader gets the row for its environment if there is one, else the row for all environments. A row only for other environments gives it nothing.

A project’s row overrides its workspace’s of the same key. The project’s list shows the workspace’s rows that reach it, marked Workspace, until it sets the key itself.

A running app’s rows are bound by g1t when it puts the app up; they never pass through the build’s sandbox. A row of a Workers project’s own vars with the same name is replaced.

Secrets go only to trusted runs:

  • pushes, schedules, manual runs and the merge queue;
  • pull requests whose author has the Write role or higher on the repository, a member or an outside collaborator;
  • pull requests from g1t’s agents.

Anyone else’s pull request, such as one from a fork or by someone with Read or Triage (who may open one on a private repository too), runs its workflows, and builds its preview, with config only: no secrets, and an empty G1T_TOKEN.

Every trusted workflow job gets ${{ secrets.G1T_TOKEN }}: a token of the workspace’s own for the run, which acts on g1t as the workspace and expires when the job could no longer be running. ${{ secrets.GITHUB_TOKEN }} and ${{ github.token }} are the same token, so workflows written for GitHub work unchanged.

- name: Open an issue when the nightly build fails
if: failure()
run: |
curl -X POST https://api.g1t.sh/repos/${{ github.repository }}/issues \
-H "Authorization: Bearer ${{ secrets.G1T_TOKEN }}" \
-d '{"title":"Nightly build failed"}'

G1T_TOKEN can read secrets’ names but never change secrets or variables, so a workflow cannot rewrite what it runs with. Neither can any workspace access token: use a person’s token, or the site.

The routes are GitHub’s, and calls written for GitHub work unchanged: a key named without an id or environments is the key’s row for all environments.

Tool Route
list_actions_secrets GET /repos/{owner}/{repo}/actions/secrets
set_actions_secret PUT /repos/{owner}/{repo}/actions/secrets/{key}
delete_actions_secret DELETE /repos/{owner}/{repo}/actions/secrets/{key}
list_actions_variables GET /repos/{owner}/{repo}/actions/variables
set_actions_variable POST /repos/{owner}/{repo}/actions/variables, PATCH …/variables/{key}
delete_actions_variable DELETE /repos/{owner}/{repo}/actions/variables/{key}

A workspace’s are under /workspaces/{workspace}/actions/secrets and …/variables. Beyond GitHub’s fields, a row takes:

Field
id The row to change or remove, from a list.
available_to ["workflows"], ["deployments"] or both. availableTo works too.
environments ["production"], ["preview", "staging"]; [] for all.
projects A workspace’s row: project names; [] for every one. (repositories is read the same way.)
note Where to rotate it, or who to ask.
curl -X PUT https://api.g1t.sh/repos/acme/web/actions/secrets/STRIPE_KEY \
-H "Authorization: Bearer $YOUR_TOKEN" \
-d '{"value":"sk_live_…","environments":["production"],"available_to":["deployments"]}'

Unlike GitHub’s, a secret is sent as plain value over HTTPS, not encrypted to a public key.