# Actions variables

> Let a By Dawn agent create and update the GitHub Actions variables a repo's workflows read, on one repo or shared across your project's repos.

This page shows you how a By Dawn agent sets the GitHub Actions variables a workflow needs, such as a deploy region or a
feature flag, without asking a person to do it on GitHub. By the end you'll know the command, where a variable can
land, and what has to be turned on first.

An **Actions variable** is a plain-text value GitHub hands to a repo's workflows as `vars.NAME`. An agent can't set
one with `gh`, because the git credential it works with can only read and push code. So it asks By Dawn instead, and By Dawn
writes the variable through its own GitHub App. The App's credential never leaves By Dawn, and every change is recorded on
the agent's ticket.

> **Caution:** A variable isn't a secret. Anyone who can read the repo can read its variables, and `saw variable list` prints their
> values. Keep API keys and tokens in [Secrets](https://docs.bydawn.com/secrets/), and use a [repo bootstrap policy](https://docs.bydawn.com/repo-bootstrap/#why-secrets-are-pushed-by-an-agent)
> to push them into a repo's Actions secrets.

## Set a variable

A worker runs:

```
saw variable set <name> --body <value> [--repo <repo>] [--org] [--repos a,b]
```

Agents can also call the same thing as the `saw_variable_set` tool. Where the variable goes depends on the flags:

| You pass | Where the variable lands |
| --- | --- |
| Neither `--repo` nor `--org` | The repo the worker is working in. |
| `--repo <repo>` | That repo. It has to be one of the ticket's repos. |
| `--org` | Your GitHub organization, shared only with the ticket's repos. |
| `--org --repos a,b` | Your GitHub organization, shared with the repos you name. Each one has to be in the ticket's project. |

Names follow GitHub's rules: letters, digits and `_`, not starting with a digit or with `GITHUB_`. A value can span
several lines, such as a JSON blob.

For example, to set a variable on the repo the worker is in, then on another of the ticket's repos:

```
saw variable set DEPLOY_ENV --body staging
saw variable set DEPLOY_ENV --body staging --repo web
```

And to set one variable that two of the project's repos share:

```
saw variable set AWS_REGION --body us-east-1 --org --repos api,web
```

By Dawn answers with the variable's name, where it lives (`scope`: `repo` or `org`), the repo or repos it's on, and what
happened (`result`):

```json
{ "name": "AWS_REGION", "scope": "org", "repos": ["api", "web"], "result": "created" }
```

| Result | Meaning |
| --- | --- |
| `created` | The variable didn't exist, so By Dawn created it. |
| `updated` | The variable existed, and By Dawn changed its value or shared it with more repos. |
| `unchanged` | It already had this value and these repos, so nothing changed. Running the same command twice is safe. |

## List variables

```
saw variable list [--repo <repo>] [--org]
```

The `saw_variable_list` tool does the same. Without a flag it lists the variables of the repo the worker is in, with
`--repo` those of another of the ticket's repos, and with `--org` the organization's. Each one comes back with its
name, value and, when GitHub says, when it last changed. An organization variable also has its `visibility` on GitHub.

Listing works from any run. Setting doesn't work from a read-only run, such as planning or review, because it changes
what the repo's CI runs with.

## Organization variables

An organization variable is shared by several repos, so By Dawn only lets an agent set one when a project admin has said
it may. Turn on **Agents may set org Actions variables** in **Settings › This project › Repos**. It's off
to start with, and only project admins and org admins can change it. Variables on the ticket's own repos don't need
it.

Even with it on, an agent's organization variable stays inside the project:

- By Dawn creates it visible to **selected repositories** only, never to every repo in the organization.
- The repos it's shared with must be in the ticket's project. Without `--repos`, they're the ticket's repos.
- If the variable already exists, By Dawn adds your repos to the ones it's shared with. It never takes a repo away.
- By Dawn won't touch an existing variable that's visible to all the organization's repos, or to all its private ones,
  or that's already shared with a repo outside the project. Ask an organization owner to change it on GitHub.

## When By Dawn refuses

When By Dawn can't set a variable, the command fails with a **slug**, a fixed error code you can branch on (see
[Responses and errors](https://docs.bydawn.com/developers/responses-and-errors/)):

| Slug | Why | What to do |
| --- | --- | --- |
| `agent_org_variables_disabled` | `--org` on a project where **Agents may set org Actions variables** is off. | A project admin turns it on, or set the variable on the repo instead. |
| `github_variables_permission_missing` | By Dawn's GitHub App hasn't been given the **Variables** permission yet. The message links to the installation. | An organization owner accepts it (see below). |
| `github_variable_out_of_scope` | The organization variable already exists and is visible beyond the project's repos. | An organization owner changes or renames it on GitHub. |
| `github_repo_not_covered` | By Dawn's GitHub App can't reach the repo. | Add the repo to the installation's repository access on GitHub. |

The command also refuses, before asking By Dawn, when you pass both `--repo` and `--org`, when the repo isn't one of the
ticket's, or when the run is read-only.

## Permissions on GitHub

Setting variables needs two permissions on By Dawn's GitHub App: the repository permission **Variables** and the
organization permission **Variables**, both read and write. If your organization installed the App before it asked
for them, GitHub holds the request until an owner of the GitHub organization opens the installation, reviews the
request and accepts it. Until then, By Dawn answers `github_variables_permission_missing` with a link to that page.

By Dawn keeps these permissions inside its own GitHub service. For each change it uses a credential that can only touch
variables, on that one repo or on the organization's variables, and never hands it to the agent.

## Every change is on the ticket

Each variable an agent sets adds a row to its ticket's timeline: the variable's name, whether it's a repo or an
organization variable, the repos it's on, and whether it was created, updated or unchanged. The value isn't recorded.

## Where to go next

- [Repo bootstrap](https://docs.bydawn.com/repo-bootstrap/): give every new repo the same variables, secrets, ruleset and files.
- [Secrets](https://docs.bydawn.com/secrets/): give agents the credentials that mustn't be readable in a repo.
- [Repos](https://docs.bydawn.com/repos/): the other agent switches in a project's repo settings.

Source: https://docs.bydawn.com/actions-variables/
