Evidence from agents and laptops
Updated
This guide lets a coding agent or a person run a deploy's checks before pushing, so the deploy's plan counts the results and skips those checks.
Before you begin
- Set up the deploy: see Deploys.
- Install Docker or Podman where checks run isolated. Environment variables has the settings for both.
- For
hushrun run -- COMMANDalone, see Agents in sandboxes instead.
Run the checks before pushing
hushrun run --all --isolated --worktree--worktreedigests the files asgit add -A && git commitwould record them now, so the evidence is about the commit you're about to make.--allruns every check the deploy requires that has no valid evidence yet.--isolatedruns each check in its pinned image and platform, with Docker or Podman, on an export of exactly the digested files. The check gets no network unless it declares one, and only the variables itsenvnames. It never gets a secret or the signing key.
The evidence records custody isolated, with the image, platform and network it ran with. The deploy's plan counts it, unless the repository takes CI's evidence only.
Then commit exactly what ran, with no other change, and push. If the files differ, so does the digest, and CI runs the checks itself.
Pin the images CI runs checks in
An isolated run needs the check's image, pinned by digest, and its platform. A check that pins them counts evidence only from that image and platform, so pin the image your CI job already uses:
checks:
unit:
run: go test ./...
image: golang@sha256:<digest of the image CI uses>
platform: linux/amd64
env: [GOFLAGS] # the only variables the check sees
network: none # the default- CI must run the check in the same image. With the reusable workflow on GitHub, set
isolated: true. Otherwise run the CI job in that image, and pass it tohushrun runas--environment-image <image>@sha256:…. network: openis for a check that downloads.restrictedruns it on the Docker or Podman network thatHUSHRUN_RESTRICTED_NETWORKnames, one whose egress you restrict.- A check whose
envnames a secret never runs isolated: keep it in CI. See Names treated as secrets.
Give each agent a key
An agent signs with the machine key that comes with its agent token. Its events count because the agent is one of the org's signers, so nothing goes in hushrun.yaml. An org admin makes the token, in the repository or on the dashboard's Agents page:
hushrun token create --agent claude-codeAt a terminal, it shows one string, once, with the token and the key inside. In CI, or where stdout or stderr isn't a terminal, it doesn't show: --format json gives it to a script as hushrun_agent. Give each sandbox the string as HUSHRUN_AGENT. Every sandbox of the agent signs as that one machine.
- The token lasts 30 days unless
--expiressays otherwise, 365 days at most. The same token serveshushrun run -- COMMAND's results. - The key never goes in the repository, where
--worktreewould digest it. hushrun refuses a key file inside the repository, and an isolated run refuses to export one. - Revoking the token, with
hushrun token revoke claude-codeor in the dashboard (Agent tokens), stops what the agent signs from then on from counting. What it signed before keeps counting. HUSHRUN_SIGNING=machine hushrun doctorsays whether hushrun's server counts the machine, and as whose.HUSHRUN_INVOKED_BY=agent:<name>is optional: events record it, and plans ignore it.
A sandbox set up with HUSHRUN_TOKEN and HUSHRUN_MACHINE_KEY keeps working. See Agents in sandboxes.
Sign in on people's machines
A teammate's machine counts with no token to make. hushrun login registers it, with a key hushrun keeps beside its credentials, never in a repository. Its events count while its owner is a member of the org, unless the repository takes CI's evidence only.
Checks that pin no image can run on the machine itself, with hushrun run --all --worktree. That evidence records custody local.
hushrun whoamishows the machine's key id.hushrun logoutrevokes the sign-in and the machine. What it signed before keeps counting.- A machine unused for 90 days is revoked, and
hushrun loginbrings it back. A person has at most 20 machines in an org. - In CI, hushrun signs with a machine key only when
HUSHRUN_MACHINE_KEYorHUSHRUN_MACHINE_KEY_FILEgives one, so a sign-in left on a runner never signs as that person.
See Machines to list or revoke the organization's machines.
Keep deploys to CI's evidence
An admin can turn on CI reuses only CI's results for the repository, so its deploys count no agent's or laptop's evidence. It isn't in hushrun.yaml, so no pull request, an agent's included, can turn it off. See CI's evidence only, and why a GitLab project shouldn't turn it on.
Tell the agent
npx hushrun init writes what agents read and installs the pre-push hook. Both come down to one command:
$ hushrun ready a0b1c2d isn't ready: CI would run 1 check again. missing unit no pass yet for this exact code Run these here, then push: hushrun run --isolated unit
The hook refuses an agent's push with the same list. hushrun ready lists the deploy's checks only in a hushrun.yaml with a deploy block. A check nothing here can change stays with CI, and doesn't count against the code: one in a repository that takes CI's evidence only, one that needs a secret, or one pinned to an image on a machine with no Docker or Podman.
If something is refused
| Message | What to do |
|---|---|
pins no `image`, so it can't run isolated | Pin the check's image, by digest (above) |
an isolated run never passes secrets in | Keep that check in CI, or drop the variable from its env |
declares `network: restricted`, which hushrun can't provide | Set HUSHRUN_ to a network whose egress you restrict |
isn't on PATH: install Docker or Podman | Install one, or set HUSHRUN_ |
collides with another digested path | Two paths differ only in case: set HUSHRUN_ to a case-sensitive directory |
here digests to …, not … | The checkout isn't the content named: run where it is, with - for uncommitted changes |
a machine's key must never be committed | Keep the key in hushrun's configuration directory, or set HUSHRUN_ outside the repository |
this command signs events | Sign in with hushrun login, or set HUSHRUN_ |
no valid signature by a machine of a member or an agent of the org | Sign in with hushrun login, or give the agent its string as HUSHRUN_ |
Details
Names treated as secrets
An isolated run refuses any env name that:
- contains
TOKEN,SECRET,PASSWORD,PASSWD,PASSPHRASE,CREDENTIAL,PRIVATE,AUTH,ACCESS_KEY,APIKEY,DATABASE_URLor_KEY_; - ends in
_KEY,_PAT,_DSNor_PWD; - is one of a few more, such as
GOOGLE_APPLICATION_CREDENTIALS,REDIS_URLandSSH_AUTH_SOCK.
The list is a safety net: name in env only what the check needs.
Next
- The planner: how a deploy decides what to do.
- GitHub Actions: run checks in CI in the same images, with
isolated: true. - For coding agents: what agents read and do before a push.