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.
Let instance admins read every repository
381d6aac38ab785d879fa82a6b8397ce6f543bab · Keenan Nemetz · 14d ago · parent 074ae160
Let instance admins read every repository An instance administrator can already rewrite any repository's ACL, so hiding its content only hides what they govern. Raise them to at least read in the web and SSH paths, preserving any higher explicit role, and enforce the read rule on SSH upload-pack, where any authenticated key could previously clone a private repository by name. Anonymous HTTP clone still answers 404 because it carries no identity. Group the admin surface into Repositories and Users tabs with a shared header, and teach Page.Section to mark the active tab.
server/web/static/vole.css +19−3
| @@ -243,20 +243,23 @@ img { max-width: 100%; } | |||
| 243 | 243 | /* The tab pages are a level below the repository identity: their own headers | |
| 244 | 244 | stay small. Top-level pages (Runners, Account, Status, Admin) keep the | |
| 245 | 245 | home-page header scale. */ | |
| 246 | .repohead + .page-head { | ||
| 246 | .repohead + .page-head, | ||
| 247 | .page-head.subhead { | ||
| 247 | 248 | align-items: flex-start; | |
| 248 | 249 | gap: 16px; | |
| 249 | 250 | padding: 0; | |
| 250 | 251 | margin-bottom: 12px; | |
| 251 | 252 | border-bottom: 0; | |
| 252 | 253 | } | |
| 253 | .repohead + .page-head h1 { | ||
| 254 | .repohead + .page-head h1, | ||
| 255 | .page-head.subhead h1 { | ||
| 254 | 256 | font-size: 18px; | |
| 255 | 257 | line-height: 1.35; | |
| 256 | 258 | letter-spacing: -0.005em; | |
| 257 | 259 | margin: 0 0 3px; | |
| 258 | 260 | } | |
| 259 | .repohead + .page-head .page-sub { font-size: 12.5px; } | ||
| 261 | .repohead + .page-head .page-sub, | ||
| 262 | .page-head.subhead .page-sub { font-size: 12.5px; } | ||
| 260 | 263 | ||
| 261 | 264 | @media (max-width: 720px) { | |
| 262 | 265 | .repo-title { padding: 18px 0 10px; } | |
| @@ -1186,6 +1189,19 @@ details[open] > summary .tree-chevron { transform: rotate(90deg); } | |||
| 1186 | 1189 | .page-head-actions .clone-pop { left: auto; right: 0; } | |
| 1187 | 1190 | .page-sub { color: var(--fg-muted); font-size: 13px; margin: 0; max-width: 80ch; } | |
| 1188 | 1191 | ||
| 1192 | /* Admin is a top-level page with its own tabs, so its title does not need the | ||
| 1193 | usual rule; the tab bar is the divider. Detail pages under it use .subhead. */ | ||
| 1194 | .page-head.admin-head { padding-bottom: 8px; margin-bottom: 0; border-bottom: 0; } | ||
| 1195 | .admin-tabs { border-bottom: 1px solid var(--border); margin-bottom: 20px; } | ||
| 1196 | .toolbar { | ||
| 1197 | display: flex; | ||
| 1198 | align-items: center; | ||
| 1199 | justify-content: space-between; | ||
| 1200 | gap: 12px; | ||
| 1201 | margin: 0 0 12px; | ||
| 1202 | } | ||
| 1203 | .toolbar .muted { font-size: 12px; } | ||
| 1204 | |||
| 1189 | 1205 | @media (max-width: 720px) { | |
| 1190 | 1206 | .page-head { padding: 18px 0 16px; } | |
| 1191 | 1207 | .page-head h1 { font-size: 22px; } | |