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.
Store repository secrets encrypted, with a CLI and a settings form
0c40a1d3b48eb0ade37334f62ee526c371ecb61c · Keenan Nemetz · 7d ago · parent 122cbe4f
Store repository secrets encrypted, with a CLI and a settings form A repository has values that cannot live in its code: a deploy key, a registry token, a staging password. They are now stored in data/secrets.db, sealed with AES-256-GCM under data/secrets.key, and read through one store that records every read and every change. The key is a separate file, and secrets_key can move it, so a backup of the data directory can be a backup of ciphertext rather than of plaintext. `vole secret list|set|get|rm` asks the instance over the key the caller already pushes with, since the store is server-side. set reads the value from stdin or a file and never from the argument list; get writes the value and nothing else. The maintainer role is the capability: the accounts that approve work and allow CI own the credentials those jobs will use. The repository's Settings tab gains the same list — names, versions, who changed one, when a value was last read — with set, replace and delete. It never renders a value, and a maintainer who is not an admin now reaches that page for this section alone. Values are limited to what one environment variable can carry: 128 KiB for NAME=value, valid UTF-8 and no NUL. A longer value could never reach a step, and the refusal says so. Slice 1 of #154.
docs/cli.md +30
| @@ -25,6 +25,36 @@ Options follow Git's conventions: `--long value`, `--long=value`, `-o value`, | |||
| 25 | 25 | end option parsing. Options may appear before or after arguments. `vole help | |
| 26 | 26 | <command>` and `vole <command> -h` print that command's usage. | |
| 27 | 27 | ||
| 28 | ## Secrets | ||
| 29 | |||
| 30 | A repository's secrets are the values its maintainers share, stored on the | ||
| 31 | instance, encrypted, and never in the repository: | ||
| 32 | |||
| 33 | ```sh | ||
| 34 | vole secret list <repo> | ||
| 35 | vole secret set <repo> <NAME> # the value is read from stdin | ||
| 36 | vole secret set <repo> <NAME> --from-file key.pem | ||
| 37 | vole secret get <repo> <NAME> # the value, and nothing else | ||
| 38 | vole secret rm <repo> <NAME> | ||
| 39 | ``` | ||
| 40 | |||
| 41 | `set` reads the value from standard input or a file and never from the command | ||
| 42 | line: an argument is visible to every process on the host and lands in shell | ||
| 43 | history. On a terminal it prompts without echoing; from a pipe it removes one | ||
| 44 | trailing newline, so `echo "$TOKEN" | vole secret set demo DEPLOY_KEY` stores the | ||
| 45 | token and not the line ending. `get` writes the value with no newline added, so it | ||
| 46 | can be redirected to a file. | ||
| 47 | |||
| 48 | `set` needs the maintainer role in that repository, and every read and change is | ||
| 49 | recorded in `data/audit.log`. `list` shows names, versions, who last changed one, | ||
| 50 | and when a value was last read — never a value. The same values appear on the | ||
| 51 | repository's **Settings** tab, which is write-only: a saved value is not shown | ||
| 52 | again. | ||
| 53 | |||
| 54 | Names are upper-case letters, digits and `_`, so a name can be read as an | ||
| 55 | environment variable. A value is limited to 128 KiB, the most one environment | ||
| 56 | variable can carry. | ||
| 57 | |||
| 28 | 58 | ## Instance | |
| 29 | 59 | ||
| 30 | 60 | ```sh | |