# Transparency log

This page explains how every hushrun command checks hushrun's server instead of trusting it. The server keeps each repository's events in an append-only log, and signs what it says about that log with a key `hushrun.yaml` pins.

## The log key in hushrun.yaml

Every write to a repository on hushrun is a leaf of an append-only Merkle log. The server signs these with the repository's **log key**:

- the log's checkpoints;
- each listing it answers;
- its answer about who counts.

`hushrun.yaml` names that key at its top level, so the server can't vouch for itself:

```yaml title="hushrun.yaml"
transparency_log:
  origin: api.hushrun.com/l/acme/api
  key: "ed25519:…"
```

- `npx hushrun init` writes these lines when the server tells it the key. Otherwise, `hushrun doctor` prints them.
- `origin` is the repository's URL on hushrun without its scheme, and `key` is the log's Ed25519 public key.
- hushrun reads them as committed, so changing them is a reviewed change.

## What every command checks

With the key pinned, every command that reads or writes the repository's events checks what the server answers:

- the receipt of each write;
- the signed statement of each listing;
- the signers answer, which says who counts;
- that every checkpoint it meets, the server's own and those recorded inside events, belongs to one history.

A check that fails ends the command with exit code 6. Until `hushrun.yaml` names the key, hushrun checks none of this, and warns on every command.

`hushrun plan --start` records the listings its decision read in its `started` event, for monitors to check. `hushrun mark deployed` refuses an attempt without that event, so every deploy has one.

## Monitor the log

A listing that leaves an event out could hide a failure from a plan. `hushrun repository monitor` finds it afterwards:

```bash
hushrun repository monitor --state monitor.json
```

- It replays the repository's log against the server's latest signed checkpoint, which must extend the one the last run kept in `--state`.
- It checks every checkpoint and listing plans recorded, every deletion against an org admin's signed statement, and every map the server committed to.
- It exits 5 when the server contradicts its own log, and prints the server's signed statements as proof. It exits 0 when everything agrees.
- It needs only read access, and the log key in `hushrun.yaml`.

The monitor that counts is one the server's operator doesn't run. Run it from your own CI, every hour:

```yaml title=".github/workflows/hushrun-monitor.yml"
name: Monitor the hushrun repository
on:
  schedule:
    - cron: "17 * * * *"
  workflow_dispatch:

concurrency:
  group: hushrun-monitor
  cancel-in-progress: false

jobs:
  monitor:
    runs-on: ubuntu-latest
    # id-token: write lets hushrun ask for an ID token whose audience is the repository's URL.
    permissions: { contents: read, id-token: write }
    steps:
      - uses: actions/checkout@v4                       # hushrun.yaml names the log key
      - uses: hushrun/hushrun/action/setup@main        # pin to a release commit
        # The newest hushrun release; `with: { version: 0.6.0 }` pins one.
      # The newest checkpoint the last run verified: a server that rolls back between runs
      # contradicts it.
      - uses: actions/cache/restore@v4
        with:
          path: hushrun-monitor.json
          key: hushrun-monitor-${{ github.run_id }}
          restore-keys: hushrun-monitor-
      - run: hushrun repository monitor --state hushrun-monitor.json --format json > monitor.json
      - if: always()
        run: jq '{ok, checkpoint: .checkpoint.size, checked, findings}' monitor.json
      - uses: actions/cache/save@v4
        if: success()
        with:
          path: hushrun-monitor.json
          key: hushrun-monitor-${{ github.run_id }}
      - uses: actions/upload-artifact@v4               # the findings and their proofs, if any
        if: failure()
        with: { name: hushrun-monitor, path: monitor.json }
```

## Who can read and write

A pipeline that could delete or overwrite an event could remove a `failed` result, and unblock a digest that never passed. Signatures can't prove an event is missing, so hushrun's server keeps events append-only:

| Who | Events | Delete |
|---|---|---|
| CI, with its ID token or a writer token | Append and read | Never |
| A member or an agent, from a registered machine | Append what that machine signed, and read | Never |
| Org admins and owners | Read | Only with `hushrun repository gc` |

- A token has a role: `reader` reads, `writer` also appends events, and `admin` also deletes. hushrun creates each event only if it doesn't exist yet, and the roles keep a client that misbehaves from overwriting or deleting one.
- A GitHub Actions job with `id-token: write` gets the writer role for the repository its ID token names. Other CI uses an agent token and its machine key ([GitLab CI](https://hushrun.com/docs/deploy/gitlab.md#variables)).
- An org admin makes repository tokens, `hrl_…`, for monitors and scripts, on the repository's page in the dashboard. They go in `HUSHRUN_REPOSITORY_TOKEN`, or come from the command in `HUSHRUN_REPOSITORY_TOKEN_COMMAND`.
- hushrun reads tokens only from the environment, never from the repository, and never logs them.
- `HUSHRUN_REPOSITORY_TOKEN` goes only to a URL that `HUSHRUN_REPOSITORY_URL` or `--repository-url` names. A URL that only `hushrun.yaml` names gets a CI job's ID token. Outside CI, it gets the login you made for its origin, or an agent token when it's on hushrun's own host.

## Delete old events

An org admin or owner deletes old events from their signed-in machine, first with `--dry-run`:

```bash
hushrun repository gc --older-than 180d --dry-run
```

It keeps the newest deployment of each scope, and the events of its digest. On a repository that keeps a log, it signs each deletion with the admin's machine. A deletion is then never the server's own doing, and monitors report any deletion without such a signature.

## Next

- [Who counts](https://hushrun.com/docs/deploy.md#who-counts): whose signed events count.
- [Commands](https://hushrun.com/docs/reference/cli.md#hushrun-repository-monitor): every flag of the monitor.
