# Administration

> For the complete documentation index, see [llms.txt](/llms.txt)

`https://<box>/_guard/admin`, linked from the header of every guard page.
Administrators only; a read-only user who opens it sees *"Only
administrators may open this page."*

The page is server-rendered and works without JavaScript. Every action on
it requires an administrator session and is checked for its `Origin`.

## Environments

One row per `<project>/<environment>` the box serves: the bundle it is
running (`main@1a2b3c4`, with a `wip` tag when the bundle was packed from a
tree with uncommitted changes) and a link to the environment's **values**
page. See [Environments & values](/box/environments-and-values/).

## Users

Everyone who has ever signed in. Nobody is provisioned here — a person's
record is created at their first login, from your directory.

| Column | Meaning |
|---|---|
| **User** | Display name, with the address underneath; a `you` tag on yourself. |
| **Role** | `admin` or `readonly`. An `override` tag means an administrator pinned the role on this box; hovering shows what the directory says. |
| **Status** | `active` or `disabled`. |
| **Last login** | When they last signed in. |

The heading shows `seats <used>/<total> in use` — see
[Seats](/box/sign-in/#seats).

### Actions

- **make admin** / **make readonly** — pin a role on this box. The override
  wins over whatever the directory grants, survives re-login and the
  periodic re-check, and applies to the person's live sessions
  immediately. Use it to fix a mapping now, without waiting for a change
  at your identity provider.
- **clear override** — hand the decision back to the directory.
- **disable** — shut the person out of this box without touching your
  directory. Their live sessions end at once, and their next login is
  refused (`login.refused`, reason *account disabled on this box*). A
  disabled person does not hold a seat.
- **enable** — undo a disable.

Role and status changes are recorded as `role.changed` and
`user.status.changed`.

## Active sessions

Who is signed in right now: user, role, the environment they selected, and
when the session started. **kill** ends one session immediately
(`session.revoked`, reason *ended by <you>*). Killing your own session
signs you out.

## Continuous integration

`https://<box>/_guard/ci` creates the GitHub App through which the box
reports checks on your pull requests and deployments. GitHub asks you to
confirm and sends you back; the box keeps the App's key and the guard
keeps nothing. The App is asked for **checks: write** and **pull requests:
read** — it is never given access to your code. Creating the App is
recorded as `ci.app.installed`.

Install the App on the repositories the box should watch, from the App's
page on GitHub. How events map to environments is described in
[Pushing suites](/box/pushing-suites/#from-a-github-webhook).

## Notifications

`https://<box>/_guard/notifications` is where a project's channels — Slack,
Telegram, a webhook — and the rules that send to them are managed: add,
edit, switch off, send a test event; mute a series or the project; set
quiet hours. Every change is recorded (`notify.channel.*`, `notify.rule.*`,
`notify.test.sent`, `notify.mute.*`, `notify.series.reset`,
`notify.quiet-hours.*`), never a secret. A readonly session sees the page
without its forms. What is announced, and when, is described in
[Notifications](/box/notifications/).

## The audit trail

The box writes an append-only JSONL file per UTC day, meant for your SIEM
to collect. The guard never reads it back to make decisions. A write
failure is logged and never turns into a refused login.

**Recent audit** on the Administration page shows the last 50 records as a
table — when, event, user, client address, a one-line summary — with the
raw JSON record folded under each row. If the box has no audit directory
configured, the page says so and events go to the process log instead.

Every record carries `kind` and `at`; events that identify a person carry
`user` (`issuer`, `subject`, `displayName`, `email`), and events from a
browser carry `ip`.

| `kind` | Meaning | Fields |
|---|---|---|
| `login.succeeded` | A sign-in completed. | `providerId`, `role`, `user`, `ip` |
| `login.refused` | A sign-in was refused: bad credentials, disabled account, no mapped group, unverified email, directory unreachable. | `providerId`, `reason`, `user` (when known), `ip` |
| `logout` | The person signed out. | `user`, `ip` |
| `seat.denied` | Refused because every licensed seat is held. | `user`, `seats`, `seatsUsed`, `ip` |
| `session.revoked` | A session ended other than by logout: a directory re-check, an administrator's **kill**, or a provider removed from the configuration. | `user`, `reason` |
| `role.changed` | A live session's role moved. | `user`, `from`, `to` |
| `user.status.changed` | An administrator disabled or enabled someone. | `user`, `status`, `by` |
| `ci.app.installed` | A GitHub App was created for this box — the moment it gains the ability to write checks on your repositories. | `user`, `app`, `by` |
| `env.value.set` | An environment's target, a variable or a secret was set from the values page. Name only, never the value. | `user`, `environment`, `valueKind`, `name` |
| `env.value.removed` | The same, removed. | `user`, `environment`, `valueKind`, `name` |
| `secret.revealed` | An administrator looked at a secret's value — shown on the page (`show`) or copied to the clipboard (`copy`). One event per look. Names only. | `user`, `environment`, `names`, `how`, `ip` |
| `env.values.replaced` | An environment's layers were replaced as a whole from the JSON editor. Names by layer. | `user`, `environment`, `set`, `removed` |

`environment` is always `<project>/<environment>`. No event ever carries a
secret's value.
