Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

#156

Let a job declare the secrets it reads

merged · by keenan 7d ago · merged into main at 4ac42680 by keenan 7d ago

keenan opened this 7d ago

Slice 2 of #154: secrets: in the workflow, delivery at lease time, and the missing-name warning.

What it adds

  • The field. secrets: on a job, one name or a list, names only. Upper-case letters, digits and _; duplicates and the runner’s own variables are refused at push. No cap on how many a workflow declares.
  • Pinning. The names are pinned on the run row beside env and artifacts, so editing the workflow afterwards cannot change what a queued run reads.
  • Delivery. At lease time the server resolves the names and sends {name, version, value} on the channel that already carries the job. The queue never holds a value, and the store records the read against the account holding the lease.
  • The runner. Writes export NAME='value' lines, POSIX-quoted, to secrets.env in the run directory it already mounts at /run/vole for an event payload, and prefixes each step with . /run/vole/secrets.env. Values never appear in an argv: --env would expose them to every process on the host, and --env-file cannot carry a line break, which is what a key has.
  • Absent is not a failure. The variable is left unset, not empty, and the log gets one line: vole: DEPLOY_TOKEN is not set for this repository, so this job runs without it. A required secret is ${DEPLOY_TOKEN:?…} in the step, so the message is the author’s.
  • The record. The attempt names {name, version} for each value the job ran with. checkRecord refuses a name the job did not declare, so a runner cannot claim a value it was not given.
  • Local runs. vole workflow run writes the same file, reading the values with the developer’s own credential from the instance the checkout’s remote names, and leaves unset what it cannot read, with a note.

Decisions worth reviewing

  • The name rule moved to ci. forge/secret now uses ci.ValidateSecretName and ci.MaxSecretBytes, so there is one rule instead of two that can drift: the store refuses a name no workflow could declare, and a workflow refuses a name no process environment could carry. Values over 128 KiB are refused when stored, with that reason.
  • The secrets file is sourced, not passed. Both obvious alternatives fail for a real key: --env-file is one NAME=value per line, so a PEM would be truncated silently, and --env puts the value in the runtime’s argument list.
  • A missing value is a log line, not a failed run. Optional secrets work, and a deploy whose token is absent fails in the deploy script with the message that script chose, rather than with a queue error nobody can act on.
  • The test runtime learned about mounts. The integration tests’ fake docker records --volume pairs so exec can resolve /run/vole (and /workspace) to the host directory. Before this, a step could not read the event payload either; the new tests are what needed it.

Not in this change

Slice 3: masking values in the log, and the remaining copy sweep. The reference page therefore says plainly that a step which prints a secret writes it to the log; that sentence is what slice 3 replaces. The two trust statements are already in docs/runner.md and docs/accounts-and-access.md, because they are true the moment delivery exists.

Checks

  • go vet ./..., GOFLAGS=-tags=sqlite_fts5 go test ./..., vole workflow check, python3 scripts/check-links.py
  • New tests: the field’s parsing and refusals; the runner’s re-validation of a leased value; shell round-trip of a value with quotes, $, backticks and a line break; the step’s source line; and two end-to-end runs — one that reads a value and one whose secret is absent, including the record and the log lines.

Discussion (0)

No discussion yet.