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/architecture.md +3−2
| @@ -66,6 +66,7 @@ auditable. | |||
| 66 | 66 | | CI logs | `data/logs/` | No; one file per attempt, back it up | | |
| 67 | 67 | | LFS files, build artifacts | `data/lfs/` | No; stored by content | | |
| 68 | 68 | | Privileged-action history | `data/audit.log` | It is the record; a privileged change that cannot be written there is refused | | |
| 69 | | Repository secrets | `data/secrets.db`, sealed under the key in `data/secrets.key` | No; back up both, and keep the key apart from the database | | ||
| 69 | 70 | | SSH host key | `data/ssh_host_ed25519_key` | No; it is the secret | | |
| 70 | 71 | ||
| 71 | 72 | Git holds the repository history. SQLite holds the account database, the CI queue | |
| @@ -123,7 +124,7 @@ backup of a repository does not carry CI history. | |||
| 123 | 124 | | Store metadata in Git, rules in SQLite | Repository content travels with clones; local settings stay local | | |
| 124 | 125 | | Passkeys, not passwords | No shared secret to phish, reset, or store; recovery is an instance-admin-issued enrollment link | | |
| 125 | 126 | | One program with separate serve and runner modes | Easy to deploy anywhere | | |
| 126 | | Keep the host key as the only secret | No signing key to manage or leak | | ||
| 127 | | Two long-term secrets: the host key, and the key that seals repository secrets | A deploy key has to live somewhere, and a value in Git is a value in every clone | | ||
| 127 | 128 | ||
| 128 | 129 | ## Using Vole as a library | |
| 129 | 130 | ||
| @@ -135,7 +136,7 @@ parts of Vole without running the `vole` command. | |||
| 135 | 136 | | `client` | Talks to an instance: metadata writes, identity lookups, file transfer, reviews, and site deploys | | |
| 136 | 137 | | `core/id`, `core/git`, `core/lfs` | Shared primitives and storage | | |
| 137 | 138 | | `forge` | Instance setup and administration | | |
| 138 | | `forge/config`, `forge/identity`, `forge/access`, `forge/repo`, `forge/index`, `forge/session` | Settings, accounts, permissions, repositories, search, and browser sessions | | ||
| 139 | | `forge/config`, `forge/identity`, `forge/access`, `forge/repo`, `forge/index`, `forge/session`, `forge/secret` | Settings, accounts, permissions, repositories, search, browser sessions, and each repository's sealed secrets | | ||
| 139 | 140 | | `metadata` | Issues, requests, releases, comments, approvals, and validation | | |
| 140 | 141 | | `ci` | Workflow validation and the job queue | | |
| 141 | 142 | | `ci/agent` | The embeddable runner: leasing, execution, and reporting | | |