Manage secrets

This guide stores a GitHub token as a Secret, makes it available to an Agent’s Computer, and later rotates and revokes it. For delivery modes, allowed origins, client requirements and what rotation and revocation guarantee, see Secrets.

The examples use the demo Project’s staging Environment, with the CLI configured (see Quickstart). With an Environment API key, omit --project and --env.

Create the Secret

Send the value on standard input so that it does not appear in your shell history or process list:

printf '%s' "$GITHUB_TOKEN" | helmr secret create GITHUB_TOKEN \
  --project demo --env staging \
  --idempotency-key secret:github-token:create --json

The response contains secret: "GITHUB_TOKEN" and metadata; it never contains the value. Use GITHUB_TOKEN unchanged in bindings, retrieval, rotation and revocation. The Console displays the same ID. List the Environment’s Secrets with helmr secret list --project demo --env staging --json.

A Secret belongs to one Environment. Create it separately in each Environment that needs it, using the same ID and the value appropriate to that Environment.

Bind it to a Computer

A binding names the Secret by ID and says how a Computer receives it: as a protected environment variable, a raw environment variable, or a file. Bindings are fixed when the Computer is created. Where they come from depends on how the Computer is created:

Computer created by Bindings used
Starting an Agent without --computer The definition’s secrets.
helmr computer create or client.computers.create Only the bindings passed in that request. The definition’s secrets are not added.

In the Template definition

Use this for Computers that Agents create for their Sessions:

import { agent, template, image } from "@helmr/sdk"

export const reviewerComputer = template({
  id: "reviewer",
  image: image("reviewer")
    .from("debian:bookworm-slim")
    .run(["sh", "-ceu", "apt-get update && apt-get install -y gh"]),
  resources: { cpu: 1, memory: "2GiB" },
  secrets: [
    {
      secret: "GITHUB_TOKEN",
      env: { name: "GH_TOKEN", mode: "protected", allowedOrigins: ["https://api.github.com"] },
    },
  ],
})

export const reviewer = agent({
  id: "reviewer",
  template: reviewerComputer,
  async turn() {
    // Processes started here, such as `gh api user`, see GH_TOKEN.
    return { ok: true }
  },
})

Deploy the project. Registration resolves every secrets and prepareSecrets identifier in the target Environment and rejects missing or revoked Secrets. The same compiled bundle can deploy to multiple Environments, each with its own active GITHUB_TOKEN value. Computers created by Agent starts after the Deployment is promoted get the binding. Existing Computers keep the bindings they were created with.

When creating a Computer

Write the bindings to a file and pass it to helmr computer create:

[
  {
    "secret": "GITHUB_TOKEN",
    "env": { "name": "GH_TOKEN", "mode": "protected", "allowedOrigins": ["https://api.github.com"] }
  }
]
helmr computer create reviewer --project demo --env staging \
  --key github-review --secrets-file secrets.json \
  --idempotency-key computer:github-review

With the SDK:

const computer = await client.computers.create({
  template: "reviewer",
  key: "github-review",
  idempotencyKey: "computer:github-review",
  secrets: [
    {
      secret: "GITHUB_TOKEN",
      env: { name: "GH_TOKEN", mode: "protected", allowedOrigins: ["https://api.github.com"] },
    },
  ],
})

To run an Agent on this Computer, start it with --computer COMPUTER_ID (or computer: { id } in the SDK).

Choose the delivery mode

Binding Use when
env: { name, mode: "protected", allowedOrigins } The tool sends the credential in an HTTP header to known HTTPS origins, as gh does with GH_TOKEN. The Computer only sees a placeholder.
env: { name, mode: "raw" } The tool needs the real value, for example a database password or request signing.
file: { path } The tool reads the credential from a file, such as an SSH key.

Raw and file values can be read by any process in the Computer and can be kept in its saved disk. To check a binding, run a command that uses it:

helmr computer exec --key github-review --project demo --env staging \
  -- gh api user

To change a binding or its allowed origins, create a new Computer. Secrets used only by prepare go in prepareSecrets; see Prepare a Computer.

Rotate the value

printf '%s' "$NEW_GITHUB_TOKEN" | helmr secret rotate GITHUB_TOKEN \
  --project demo --env staging \
  --idempotency-key secret:github-token:rotate:2

The Secret keeps its identifier and bindings. Protected bindings use the new value on their next request; you do not need to recreate Computers or restart work. Raw and file values are delivered when work starts, so processes that are already running keep the old value. A new Computer prepared with this Secret in prepareSecrets gets a freshly prepared image.

Revoke the Secret

helmr secret revoke GITHUB_TOKEN --yes \
  --project demo --env staging \
  --idempotency-key secret:github-token:revoke

Revocation stops Helmr from providing the Secret. Protected requests that need it fail until you rotate it, and new Session processes and Commands that need its raw value are refused. Running work continues, and raw or file copies already delivered stay on their Computers.

Revoke the credential at its provider; that is the containment. Then list the Computers that received a raw value and delete the ones you no longer trust:

helmr computer list --secret GITHUB_TOKEN --project demo --env staging

Rows marked may hold (image) received the value through image preparation. In the Console, open the Secret’s Computers link for the same list.

To use the Secret again, rotate it with a new value. The same Secret becomes active with its existing bindings; creating a Secret with the revoked name is refused.

Keep credentials out of Agent input, results, logs, image steps and source. Helmr does not refresh OAuth tokens or save a tool’s credential changes back to a Secret; rotate the stored value when it changes.