RunnableLog in
A luminous secret contained inside several nested dark chambersCredential lifecycleSecrets During a Build

SEPTEMBER 01, 2026 · RUNNABLE TEAM

What Happens to Your Secrets During a Build

Engineering

A CI secret crosses several boundaries: the settings page, durable storage, the scheduler, the runner environment, a child process, and potentially its output. Protecting only the database leaves most of that journey unexplained.

Runnable treats secret handling as a lifecycle. Each stage narrows who can access the value, binds it to context, and removes it when the job boundary ends.

At rest: two layers and authenticated context

JOB-SCOPED BY DEFAULT
short-lived credential
runner / job-7f2clean Linux x64
masked output
03 / ISOLATION Create for one job. Destroy at the terminal state.

Each organization has a versioned workspace key. Each secret receives a fresh 256-bit data key, and the encrypted data key is stored beside AES-256-GCM ciphertext. The workspace key is itself wrapped by a root key outside the ordinary secret record.

Encryption context binds the ciphertext to the organization, repository or environment scope, and secret name. Moving the encrypted fields to a different tenant or scope does not create a valid secret there because decryption authenticates the original context.

Rotation can make a new workspace-key version active while retaining an older version only for decryption. Destroyed key records no longer contain wrapped key material.

At assignment: resolve the narrowest applicable scope

Organization, repository, and environment secrets are filtered against the job's authenticated tenant, repository, and selected environment. More specific scopes override broader values with the same name.

Only after a job is admitted does the assignment builder unwrap the required workspace keys and decrypt the applicable values. Plaintext keys are held for that assignment operation and zeroed when the bundle has been assembled.

A fork pull request short-circuits the process: its secret query returns no customer secrets at any scope.

At execution: credentials belong to the job

The runner receives an attempt-scoped bootstrap identity and the resolved environment for that job. GitHub repository tokens are minted from the installation for the requested repository and permissions rather than copied from a platform-wide credential.

Write access requires the workflow to request it and the GitHub App installation to grant it. OIDC requires id-token: write, is issued for the current run context, and is refused to fork pull requests.

At output: mask before retention

A RESULT YOU CAN ACT ON
RESULT 01Compatiblepilot in parallel
RESULT 02Review requirednamed assumption
×RESULT 03Unsupportedkeep on current CI
04 / BOUNDARY No score, no guesswork, and no silent fallback.

Resolved secret values join the runner's masking set before step output is streamed. Logs are retained as evidence only after masking; the durable log record should not become a second secret store.

The settings API and MCP tools never provide a read-back operation for secret values. They can list names and scopes, create a value, or replace it, but cannot turn encrypted storage into an extraction interface.

  • StoredEnvelope-encrypted with tenant and scope context.
  • ReleasedOnly for an admitted, non-fork job whose scope matches.
  • RetainedNames, scopes, audit events, and masked logs—not a value read-back path.

RUN THE EVIDENCE

Your workflows are already runnable.

Scan one before you move it. The report names what runs, what needs review, and what stays put.

Check a workflow