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.
Merge change request 01M70WES5ZZDJ6RP226WB11BBZ: Let people rename and remove their own passkeys
keenan · 21m ago
4b8c9e1d
| 1 | # Go modules |
| 2 | |
| 3 | A public repository on a Vole instance is a Go module. The import path is the |
| 4 | instance's host and the repository name: |
| 5 | |
| 6 | ```text |
| 7 | https://<host>/<repository> |
| 8 | ``` |
| 9 | |
| 10 | Vole serves the metadata the `go` command looks for, so an import path needs no |
| 11 | vanity service, no redirect, and no separate web host in front of the forge. |
| 12 | Vole itself is published this way: `rodent.software/vole`. |
| 13 | |
| 14 | ## How the lookup works |
| 15 | |
| 16 | `go get` cannot clone an arbitrary URL from an import path, so it first asks the |
| 17 | path for directions: it fetches `https://<host>/<repository>?go-get=1` and reads |
| 18 | the `<meta name="go-import">` tag in the answer. Vole answers for a public |
| 19 | repository with that repository's Git transport: |
| 20 | |
| 21 | ```console |
| 22 | $ curl -s 'https://rodent.software/vole?go-get=1' |
| 23 | <!doctype html> |
| 24 | ... |
| 25 | <meta name="go-import" content="rodent.software/vole git https://rodent.software/vole.git"> |
| 26 | ``` |
| 27 | |
| 28 | Then `go` clones the repository over the smart-HTTP transport and resolves the |
| 29 | package from the tag it finds there, exactly as it would for a module on any |
| 30 | other forge. The transport lives beside the pages: `/<repository>` is the |
| 31 | repository and `/<repository>.git` is its Git URL, so the tag's clone URL and the |
| 32 | page a person opens are the same name. |
| 33 | |
| 34 | A package inside the module (`rodent.software/vole/server/web`) resolves from the |
| 35 | same tag: the go command asks the full path first, and the tag it gets names the |
| 36 | repository prefix. That path is not a page, and it does not need to be — the |
| 37 | probe is answered before the router, for any path whose first segment names a |
| 38 | public repository. |
| 39 | |
| 40 | Add the repository to a project as usual: |
| 41 | |
| 42 | ```console |
| 43 | $ go get rodent.software/vole |
| 44 | $ go doc rodent.software/vole/server/web |
| 45 | ``` |
| 46 | |
| 47 | ## What the instance must have |
| 48 | |
| 49 | - `public_url` set to the origin people use, in `[server]` in the |
| 50 | configuration file. The metadata's import prefix is that origin's host name; |
| 51 | without `public_url` Vole falls back to the request's host, which is not |
| 52 | something the go command's discovery can rely on. |
| 53 | - The host in the import path is the host name alone. A module path cannot carry |
| 54 | a port, so an instance reached only at `https://forge.example.com:8443` can |
| 55 | still serve its pages, but its repositories are not importable paths; clone |
| 56 | them by URL instead. |
| 57 | |
| 58 | ## Which repositories answer |
| 59 | |
| 60 | Only a repository an anonymous reader may read, which is the same rule that makes |
| 61 | its pages public. The tag is fetched without credentials — that is the discovery |
| 62 | protocol — so answering for a private repository would confirm to anyone who |
| 63 | guessed the name that it exists. Vole answers 404 for those, like every other |
| 64 | private path. |
| 65 | |
| 66 | A private repository is therefore not resolvable from its import path. Clone it |
| 67 | where the build runs and point a `replace` at that checkout, or mirror the code in |
| 68 | a repository that is public. |
| 69 | |
| 70 | ## Naming |
| 71 | |
| 72 | The import path is `<host>/<repository>`, so the repository name is also the last |
| 73 | element of every import path inside the module. Every name is available for this |
| 74 | except the four the forge keeps at the root for reasons a URL cannot avoid: |
| 75 | `static` (assets), and `robots.txt`, `sitemap.xml`, and `sitemap-pages.xml` |
| 76 | (crawlers only look for those at the root). The forge's own pages live under |
| 77 | `/-/`, a prefix no repository name can start with, so `admin`, `login`, `activity` |
| 78 | and the rest are ordinary repository names. |
| 79 | |
| 80 | Because the name is the import path, renaming a repository that other modules |
| 81 | import breaks them: there is no forwarding layer in front of the forge. Rename |
| 82 | the pages, or keep the name a published module depends on. |
| 83 | |
| 84 | ## Vole's own module |
| 85 | |
| 86 | The Vole repository is `rodent.software/vole`, so fetching the source is: |
| 87 | |
| 88 | ```console |
| 89 | $ go get rodent.software/vole |
| 90 | ``` |
| 91 | |
| 92 | and building from a checkout uses the same path: |
| 93 | |
| 94 | ```sh |
| 95 | go build -tags libsqlite3,sqlite_fts5 -o vole rodent.software/vole/cmd/vole |
| 96 | ``` |
| 97 |