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.

#155

Store repository secrets encrypted, with a CLI and a settings form

merged · by keenan 7d ago · merged into main at 0c40a1d3 by keenan 7d ago

keenan opened this 7d ago

Slice 1 of #154: the store, the CLI, and the settings form.

What it adds

  • forge/secret: one encrypted value per name per repository, in data/secrets.db. Each value is AES-256-GCM with the repository id, name and version as additional data, so a row copied to another name or replayed as an older version does not open. The key is data/secrets.key (0600, created on first use, movable with secrets_key).
  • Rows are keyed by the repository’s stable id, so a rename keeps its secrets and a new repository that takes the old name inherits nothing. Deleting a repository deletes its values, through the same two-step the access rules use.
  • vole secret list|set|get|rm over the SSH verb vole-secret. The value of a set travels on stdin, never in the exec line, which both hosts can see.
  • The same list on the repository’s Settings tab: names, versions, who changed one, when a value was last read, with set, replace and delete. No page renders a value, so the form is the only half the browser gets.
  • Every read and change is a line in data/audit.log; a read that cannot be recorded is refused, the same as an access change.

Decisions worth reviewing

  • A maintainer may now open Settings. The page already hid its admin-only forms behind RepoAdmin; it is the one place the secrets belong, and duplicating it as a second page would have needed a second tab. The two tests that asserted “maintainer settings = 404” now assert that the page is reachable and that the admin fields are absent.
  • 128 KiB per value, which is the kernel’s limit for one NAME=value string in envp. A longer value could never reach a step. Valid UTF-8 and no NUL are required because the value will travel as JSON over the lease channel and then into a process environment.
  • No per-name redaction of values in the audit detail. The detail carries the name and the version; the value is the one thing that must never reach the log, and the store tests assert it does not.
  • get adds no newline, so a redirect to a file produces the stored bytes. The CLI strips one trailing newline from a piped value only, because echo token | vole secret set … is the obvious way to store one.

Not in this change

Slice 2 (secrets: in the workflow, lease delivery, the absent-secret warning) and slice 3 (log masking, the record’s {name, version}, the remaining doc sweep). The settings copy and the CLI help therefore describe what exists now, not the workflow field.

Checks

  • go vet ./..., GOFLAGS=-tags=sqlite_fts5 go test ./..., vole workflow check
  • New tests: the store (round trip, isolation by repository, row binding, key mismatch, key mode, the value rules, multi-line values, audit) and the CLI and page end to end, including that a non-maintainer is refused and that a page never contains a value.

Discussion (0)

No discussion yet.