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/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

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

#157

Mask secret values in the log as it is written

merged · by keenan 7d ago · merged into main at e82bbe7d by keenan 7d ago

keenan opened this 7d ago

Slice 3 of #154: mask the values a job was given in the log, and say where masking stops.

What it adds

  • ci/redact: one small package that replaces each delivered value with ***, holding back the last longest-1 bytes of a write so a value split across two writes is still caught. It has a Mask for a stream the caller serialises and a Writer that serialises for itself, because a command’s stdout and stderr are copied by two goroutines.
  • The attempt log masks at the point of writing (spool.SetMask), so the file the streamer sends — and therefore the instance’s copy in data/logs/ — never holds a value. The runner flushes at the end of each step, so a step’s byte range is still its own.
  • The runner’s own error text goes through the same mask, because “a runtime message cannot contain a value” should be true rather than assumed.
  • vole workflow run masks its terminal output the same way, from the values it read with the developer’s key.

What it deliberately does not catch

Written down on the reference page and in docs/runner.md rather than left to be discovered:

  • a re-encoded value — base64, hex, a URL escape, one field of a connection string;
  • a value shorter than 4 bytes, because replacing every occurrence of 1 or yes would rewrite the log and protect nothing worth calling a secret;
  • anything a step writes into an artifact, a site file or a release attachment: the mask covers the log, not the files the job chooses to publish.

Tests

  • ci/redact: a value split across three writes; longest-match where one value is a prefix of another; the 4-byte floor; a multi-line value; every write reported as taken so a program printing its own secret is not killed by a short write; concurrent writers.
  • ci/agent: the spool masks before the file (so the streamer cannot miss it), the held-back tail is flushed at seal, and a flush at a step boundary ends the range where the output ended.
  • End to end: the job in TestAJobReadsTheSecretsItDeclares now prints the value on purpose, and the log shows echoed=*** — including a value with a line break in it — while the length and step-range assertions still hold.

Docs

docs/reference/workflow-reference.md loses the “masking is not supported” line and gains the three limits above; docs/runner.md, docs/workflows.md and docs/cli.md say what a reader gets.

Discussion (0)

No discussion yet.