# Environment variables

Every variable hushrun reads: the `HUSHRUN_` ones you set, and the ones CI providers and other tools set. A command-line flag wins over its variable, as [Configuration](https://hushrun.com/docs/reference/configuration.md#sources) explains.

- An empty value counts as unset, except in two variables, where it turns something off: `HUSHRUN_BACKEND=` turns results off, and `HUSHRUN_CACHE_DIR=` the cache.
- `HUSHRUN_CONFIG`, `HUSHRUN_FORMAT`, `HUSHRUN_NO_CI_OUTPUT`, `HUSHRUN_FORCE_FULL`, `HUSHRUN_GIT_READER` and `HUSHRUN_LOG` stand in for flags, and never stop a command. The true-or-false ones also take `1`, `0`, `yes`, `no`, `on` and `off`, in any case. A value hushrun can't read is ignored, with one line on stderr, such as `hushrun: HUSHRUN_FORMAT is "xml", not text, json, env or dotenv, so it's ignored`, and the command goes on with the default. The same goes for an unknown `HUSHRUN_PROVIDER`, and for a `HUSHRUN_RUN_ATTEMPT` or `GITHUB_RUN_ATTEMPT` that isn't a positive whole number. `-q` drops these lines. A bad flag on the command line is still a usage error.
- Variables such as `HUSHRUN_MODE` and `HUSHRUN_DIGEST` are outputs hushrun prints, not settings: see [Output formats](https://hushrun.com/docs/reference/cli.md#output-formats).

## Results and sign-in

What `hushrun run` uses to find its backend, and the token it sends there. [Where results go](https://hushrun.com/docs/results.md) has the rules in full.

| Variable | Default | What it does | Secret |
|---|---|---|---|
| `HUSHRUN_BACKEND` | Unset | The organization's URL where `hushrun run` records and looks up results, such as `https://api.hushrun.com/o/acme`. It ranks first, before the backend in `package.json` and the one `hushrun login` saved. Set to nothing, it turns results off: every check runs, and nothing is recorded. A URL that isn't `https://`, or `http://` on `localhost`, `127.0.0.1` or `[::1]`, turns them off too, with a message. `hushrun login` signs in to it, and `hushrun token` manages its tokens, when no URL is given | No |
| `HUSHRUN_TOKEN` | Unset | A token for the results backend. It goes only to the backend `HUSHRUN_BACKEND` names. An agent token, `hra_…`, also goes to the repository's or the login's backend when it is on `HUSHRUN_HOST`, and to the repository's URL on that server, in CI too. An agent token's results need the key it came with, in `HUSHRUN_MACHINE_KEY` or `HUSHRUN_MACHINE_KEY_FILE`. The `hushrun token` commands never use it | Yes |
| `HUSHRUN_HOST` | `https://api.hushrun.com` | hushrun's hosted server: where `hushrun login` signs in when nothing names a backend, and `npx hushrun init` when `package.json` names none. It is the only server an agent token follows `package.json`'s backend, the login's, or `hushrun.yaml`'s repository URL to | No |

## Agents and sandboxes

For coding agents in sandboxes, and for checks that `hushrun run --isolated` runs in containers. See [Agents and sandboxes](https://hushrun.com/docs/agents.md#sandboxes).

| Variable | Default | What it does | Secret |
|---|---|---|---|
| `HUSHRUN_PROVIDER` | Detected, see [CI detection](#ci-detection) | The CI provider running hushrun, instead of detecting it: `github`, `gitlab`, `buildkite`, `circleci`, `generic` or `local`. Set `local` in a sandbox that sets `CI=true`, so that hushrun doesn't treat it as CI. Another value is ignored, with a line saying so, and hushrun detects the provider | No |
| `HUSHRUN_INVOKED_BY` | Unset | A label for who ran the command, `agent:<id>` or `human:<id>`, such as `agent:worker-1`, to tell a fleet's runs apart. Run results and signed events record it; nothing decides on it. In `hushrun run` without a stage, another form is left out with a line saying so; commands that sign events exit 2 | No |
| `HUSHRUN_MACHINE_KEY` | Unset | This machine's key itself, as PEM, for sandboxes that keep no files. It wins over the key file. An agent's is the key its token came with, which `hushrun token create` and the dashboard's Agents page show once: with an agent token, hushrun signs results only with this or `HUSHRUN_MACHINE_KEY_FILE`, never a key a sign-in left on the machine, and without either it records nothing. In CI, hushrun signs events with a machine key only when this or `HUSHRUN_MACHINE_KEY_FILE` is set | Yes |
| `HUSHRUN_CONTAINER_RUNTIME` | `docker`, else `podman`, found on `PATH` | The container runtime `hushrun run --isolated` uses: `docker`, `podman`, or the path of a Docker-compatible CLI | No |
| `HUSHRUN_RESTRICTED_NETWORK` | Unset | The Docker or Podman network, whose egress you restrict, that a check declaring `network: restricted` runs on. Without it, such a check can't run isolated, and the command exits 2 | No |

## CI

Run identity on CI other than GitHub Actions and GitLab CI, which set their own (see [Set by CI providers](#set-by-ci-providers)), and a token for GitLab's API.

| Variable | Default | What it does | Secret |
|---|---|---|---|
| `HUSHRUN_RUN_ID` | Unset | On CI other than GitHub Actions and GitLab CI, the run's id, which signed events record. There, a command that records events exits 2 without it, unless it carries out a plan, whose id it takes | No |
| `HUSHRUN_RUN_ATTEMPT` | Unset | On GitLab CI and other CI, this run's attempt, a positive whole number. Without it, commands take the plan's attempt, else 1, and `hushrun plan` counts one more than recorded. Another value is ignored, with a line saying so. GitHub Actions' attempt comes from `GITHUB_RUN_ATTEMPT`, read the same way | No |
| `HUSHRUN_RUN_URL` | Unset | On CI other than GitHub Actions and GitLab CI, a link to the run, which run results and events record | No |
| `HUSHRUN_GITLAB_TOKEN` | Unset | A GitLab project access token with `read_api`. With it, `hushrun plan` asks GitLab whether an upstream pipeline is still running, and `hushrun doctor` checks protected branches and who may set pipeline variables | Yes |

## Signing

How commands that record promotion events sign them, and what verifies signatures. All of it comes from the environment, never from the repository's files. See [Evidence from agents](https://hushrun.com/docs/promotion/evidence.md).

| Variable | Default | What it does | Secret |
|---|---|---|---|
| `HUSHRUN_SIGNING` | A set signing key means `key`; else, in GitHub Actions with an ID token, `sigstore`; else `machine`, when there is a machine key, which in CI only `HUSHRUN_MACHINE_KEY` or `HUSHRUN_MACHINE_KEY_FILE` gives; else, in CI with `SIGSTORE_ID_TOKEN`, `sigstore` | How events are signed: `key`, `sigstore` (keyless, through Sigstore) or `machine` (this machine's key, which `hushrun login` registered, or `HUSHRUN_MACHINE_KEY`). Another value exits 2, and so does a command that signs with no signer | No |
| `HUSHRUN_SIGNING_KEY` | Unset | A signing key's PEM, Ed25519 or ECDSA P-256, for `key`. It wins over `HUSHRUN_SIGNING_KEY_FILE` | Yes |
| `HUSHRUN_SIGNING_KEY_FILE` | Unset | The path of a signing key's PEM file, for `key`. An isolated run refuses a key file inside the files it exports | No; the file is a private key |
| `HUSHRUN_CUSTODY` | `ci` in CI; `isolated` for checks `hushrun run --isolated` runs; else `local` | The custody signed events claim: `local`, `isolated`, `sandbox` or `ci`. `isolated` is recorded only for `--isolated` runs; otherwise hushrun records `local`, with a warning. Another value exits 2 | No |
| `HUSHRUN_TSA` | `https://timestamp.sigstore.dev/api/v1/timestamp` | The timestamp authorities for each signature, URLs separated by commas, tried in order. `none` turns timestamps off, which keyless signing refuses | No |
| `HUSHRUN_FULCIO_URL` | `https://fulcio.sigstore.dev` | The Fulcio that certifies keyless signatures | No |
| `HUSHRUN_OIDC_ISSUER` | `https://oauth2.sigstore.dev/auth` | Outside CI, for keyless signing as yourself: where you sign in with your browser. Without a terminal, hushrun signs in only to an issuer this variable names | No |
| `HUSHRUN_OIDC_CLIENT_ID` | `sigstore` | The client id for that sign-in | No |
| `HUSHRUN_SIGSTORE_TRUSTED_ROOT` | The trust root `hushrun sigstore refresh` cached, else the one built into hushrun | The path of a Sigstore `trusted_root.json` that verifies certificates and timestamps | No |
| `HUSHRUN_SIGSTORE_TUF_URL` | `https://tuf-repo-cdn.sigstore.dev` | Another Sigstore TUF repository for the trust root. Set it with `HUSHRUN_SIGSTORE_TUF_ROOT`, or neither; with both, hushrun needs a cached trust root from `hushrun sigstore refresh` | No |
| `HUSHRUN_SIGSTORE_TUF_ROOT` | The root built into hushrun | The path of the TUF root that repository starts from | No |

## Promotion and the repository's URL

Where the promotion commands read and write the repository's events, with which token, and from which plan and `hushrun.yaml`. [Configuration](https://hushrun.com/docs/reference/configuration.md#sources) has the order, which differs in CI.

| Variable | Default | What it does | Secret |
|---|---|---|---|
| `HUSHRUN_REPOSITORY_URL` | Unset | The repository's URL on hushrun, such as `https://api.hushrun.com/l/acme/shop`. In CI it is the URL that counts: when `hushrun.yaml`'s `repository_url` names another, or `--repository-url` does, the command exits 2 | No |
| `HUSHRUN_REPOSITORY_BASE` | Unset | One URL for an organization: each repository's URL is `<base>/<repository id>`, such as `https://api.hushrun.com/l/acme/github.com/acme/shop`. In CI, the id comes from the CI provider, and `hushrun.yaml`'s `repository` and `repository_url` must agree with it, or the command exits 2. `HUSHRUN_REPOSITORY_URL` wins when both are set. It is also `hushrun adopt`'s default `--repository-base` | No |
| `HUSHRUN_REPOSITORY_TOKEN` | Unset | A token for the repository's server. It goes only to a URL that `HUSHRUN_REPOSITORY_URL` or `--repository-url` names, or in CI one `HUSHRUN_REPOSITORY_BASE` gives, never to one only `hushrun.yaml` names | Yes |
| `HUSHRUN_REPOSITORY_TOKEN_COMMAND` | Unset | A command that prints that token and nothing else, run with `sh -c` (`cmd /C` on Windows) and with `HUSHRUN_REPOSITORY_URL` set to the server's URL. hushrun reuses what it prints for 5 minutes. Its token goes where `HUSHRUN_REPOSITORY_TOKEN` goes, which wins when both are set | No; it prints one |
| `HUSHRUN_CONFIG` | `hushrun.yaml` in the content being evaluated | The path of `hushrun.yaml`, as `--config` | No |
| `HUSHRUN_PLAN_JSON` | Unset | The plan itself, as JSON, for the commands that carry one out, `run --stage`, `attest`, `mark`, `guard` and `artifact resolve`, when `--plan` isn't given | No |
| `HUSHRUN_FORCE_FULL` | `false` | `true` makes `hushrun plan` build and run every check whatever the evidence, as `--force-full` | No |

Without a token from these, the repository's server gets, in GitHub Actions, the job's ID token; else an agent token in `HUSHRUN_TOKEN`, when the server is `HUSHRUN_HOST`, in CI too; else, outside CI, the token `hushrun login` saved for that server.

## Paths and caches

`<config dir>` is `~/.config` on Linux, `~/Library/Application Support` on macOS and `%APPDATA%` on Windows; `<cache dir>` is `~/.cache`, `~/Library/Caches` and `%LOCALAPPDATA%`. [Configuration](https://hushrun.com/docs/reference/configuration.md#files) lists what each file holds.

| Variable | Default | What it does | Secret |
|---|---|---|---|
| `HUSHRUN_CREDENTIALS` | `<config dir>/hushrun/credentials.json` | The file `hushrun login` keeps its tokens in, readable by you only | No; the file holds tokens |
| `HUSHRUN_MACHINE_KEY_FILE` | `machine-key.pem` beside the credentials file | This machine's key file. hushrun refuses one inside the repository it runs in. With an agent token, and in CI, set it to the agent's key file, such as a GitLab File variable, for hushrun to sign with it | No; the file is a private key |
| `HUSHRUN_CACHE_DIR` | `<cache dir>/hushrun` | hushrun's cache: `hushrun run`'s results when no backend applies, file hashes, the tokens this machine registered with, the Sigstore trust root `hushrun sigstore refresh` keeps, and isolated runs' exports. Set to nothing, it turns the cache off, and with it the results kept on this machine | No |
| `HUSHRUN_EXPORT_DIR` | `exports` in hushrun's cache directory, else the system's temporary directory | Where `hushrun run --isolated` exports the files a check runs on. Point it at a case-sensitive directory when two paths differ only in case | No |

## The npm package

| Variable | Default | What it does | Secret |
|---|---|---|---|
| `HUSHRUN_NPM_PACKAGE` | `hushrun@^<version>` | The package `hushrun init` adds to `devDependencies`. The npm package's `hushrun` command sets it to its own name and version unless it is set | No |
| `HUSHRUN_BINARY` | Unset | Read by the npm package's `hushrun` command: a hushrun binary to run where the package has none for this platform | No |

## Output

| Variable | Default | What it does | Secret |
|---|---|---|---|
| `HUSHRUN_FORMAT` | `text` | The output format, as `--format`: `text`, `json`, `env` or `dotenv` | No |
| `HUSHRUN_NO_CI_OUTPUT` | `false` | `true` writes no CI outputs, step summaries or annotations, as `--no-ci-output` | No |
| `HUSHRUN_LOG` | `warn` | The log filter on stderr, such as `info` or `debug`, when neither `-v` nor `-q` is given. A value hushrun can't read is ignored, with a line saying so. `-q` leaves errors only | No |
| `HUSHRUN_GIT_READER` | `auto` | How hushrun reads git objects: `auto`, `gix` or `cli`. Meant for hushrun's own tests | No |

## Set by CI providers

### CI detection

hushrun takes the first of these that is `true` or `1` as the CI it runs in, unless `HUSHRUN_PROVIDER` names one. In CI, the promotion commands take the repository's URL by CI's rules; sign keylessly by default in GitHub Actions with an ID token, and elsewhere with the agent's machine key the environment gives; claim custody `ci`; and send no person's login to the repository's server, only an agent token, to `HUSHRUN_HOST`. `hushrun approve` refuses to run; and `hushrun run` records which CI a result came from, so that a later skip says `passed in CI`.

| Variable | What hushrun uses it for |
|---|---|
| `GITHUB_ACTIONS` | GitHub Actions |
| `GITLAB_CI` | GitLab CI |
| `BUILDKITE` | Buildkite, identified as generic CI: runs need `HUSHRUN_RUN_ID` |
| `CIRCLECI` | CircleCI, identified as generic CI: runs need `HUSHRUN_RUN_ID` |
| `CI` | Any other CI, generic: runs need `HUSHRUN_RUN_ID` |

### GitHub Actions

| Variable | What hushrun uses it for |
|---|---|
| `ACTIONS_ID_TOKEN_REQUEST_URL`, `ACTIONS_ID_TOKEN_REQUEST_TOKEN` | Set when the job has `permissions: id-token: write`. hushrun asks for ID tokens with them: for the results backend, for the repository's server, and for keyless signing, each with its own audience |
| `GITHUB_RUN_ID`, `GITHUB_RUN_ATTEMPT` | The run's identity, which events record, and the run's link in run results |
| `GITHUB_REPOSITORY` | The repository, `owner/name`: the id `hushrun run` records results under, the one `HUSHRUN_REPOSITORY_BASE` uses, and the default of `hushrun token create` and `hushrun adopt` |
| `GITHUB_SERVER_URL` | GitHub's address, `https://github.com` by default, for the repository's id and the run's link |
| `GITHUB_REPOSITORY_ID` | The repository's numeric id. When the server names another id as the repository's CI, hushrun exits 2 |
| `GITHUB_EVENT_NAME` | What started the run: `push`; `workflow_run` as upstream; `workflow_dispatch` and `repository_dispatch` as manual; `schedule`. `pull_request` and `pull_request_target` make it a pull request's pipeline |
| `GITHUB_EVENT_PATH` | The event's payload: the upstream run of a `workflow_run`, and the repository's default branch |
| `GITHUB_BASE_REF` | The branch a pull request merges into, which `--config-ref` must name |
| `GITHUB_REF` | The branch, from `refs/heads/…` |
| `GITHUB_SHA` | The revision the run is for |
| `GITHUB_JOB` | The job, which events record |
| `GITHUB_OUTPUT`, `GITHUB_STEP_SUMMARY` | Where `plan`, `digest`, `guard`, `attest` and `artifact` write their outputs and a step summary |
| `GITHUB_TOKEN`, `GH_TOKEN` | When set, a token with `actions: read`: `hushrun plan` asks GitHub's API whether an upstream run is still going, and `hushrun doctor` checks the default branch |
| `GITHUB_API_URL` | GitHub's API, `https://api.github.com` by default |

### GitLab CI

| Variable | What hushrun uses it for |
|---|---|
| `SIGSTORE_ID_TOKEN` | The ID token for keyless signing: on GitLab, the job's `id_tokens` entry `SIGSTORE_ID_TOKEN` with `aud: sigstore`. On other CI, any ID token Fulcio takes |
| `CI_PIPELINE_ID`, `CI_PIPELINE_URL` | The run's identity and link |
| `CI_PIPELINE_SOURCE` | What started the run: `push`; `pipeline`, `parent_pipeline` and `trigger` as upstream; `web` and `api` as manual; `schedule`. `merge_request_event` makes it a merge request's pipeline |
| `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` | The branch a merge request merges into, which `--config-ref` must name |
| `CI_COMMIT_BRANCH` | The branch |
| `CI_COMMIT_SHA` | The revision the run is for |
| `CI_JOB_NAME`, `CI_JOB_ID` | The job, which events record |
| `CI_PROJECT_URL` | The repository: the id `hushrun run` records results under, and the one `HUSHRUN_REPOSITORY_BASE` uses |
| `CI_PROJECT_ID` | The project's numeric id. When the server names another id as the repository's CI, hushrun exits 2. With `HUSHRUN_GITLAB_TOKEN`, the project hushrun asks GitLab's API about |
| `CI_PROJECT_PATH` | The project for GitLab's API, when `CI_PROJECT_ID` isn't set |
| `CI_DEFAULT_BRANCH` | The repository's default branch |
| `CI_API_V4_URL` | GitLab's API, `https://gitlab.com/api/v4` by default |

### Package managers

| Variable | What hushrun uses it for |
|---|---|
| `npm_lifecycle_event` | The script npm, pnpm, Yarn and Bun are running. `hushrun run` without NAME names the check after it, unless it is `npx`, which `npx` and `npm exec` set, or isn't a valid name |

## Other variables

| Variable | What hushrun uses it for |
|---|---|
| `NO_COLOR` | Set, it turns off colored logs under `--color auto` |
| `BROWSER` | The command that opens the sign-in page for keyless signing as yourself, at a terminal; without it, the system's opener |
| `DOCKER_CONFIG` | The directory whose `config.json` holds registry credentials, `~/.docker` by default: its `credHelpers`, `credsStore` and `auths` |
| `PATH`, `PATHEXT` | Where `hushrun run` finds the command. On Windows, a bare name is looked up with `PATHEXT`'s `.com`, `.exe`, `.bat` and `.cmd`, so `vitest` finds `node_modules\.bin\vitest.cmd` |
| `XDG_CONFIG_HOME`, `XDG_CACHE_HOME` | On Linux, the configuration and cache directories, `~/.config` and `~/.cache` by default |
