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/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Customize the instance from an instance repository

6ce635a84ad5d5d0c862d4deb4d46489dc97c677 · Keenan Nemetz · 1d ago · parent f2fd4024

Customize the instance from an instance repository

The landing page's prose was config-only, so changing it meant editing
vole.toml on the host and restarting, and the packaged service cannot write
that file. Custom CSS, assets, and a favicon had nowhere to live at all.

This adds an instance repository, modelled on GitHub's .github repository:
fixed paths in one private repository, read as data rather than executed.

    profile/README.md           the landing page introduction
    profile/private/README.md   replaces it for signed-in viewers
    profile/custom.css          loaded after the built-in stylesheets
    profile/favicon.svg         favicon override
    assets/                     served at /static/custom/assets/

forge/instancerepo reads one commit into an immutable snapshot on a two
second timer and swaps it atomically; a request never runs git, and a load
failure keeps the previous theme. Markdown goes through the issue sanitiser,
assets are an extension whitelist with size and count caps, and scripts and
HTML are not assets. The repository is private to instance admins and hidden
from the home grid and activity rail, but its files are served to visitors.

The Admin Configuration tab grows an Instance repository panel: status, the
last commit, the last load error, the clone URL, the recognized paths, and a
button that creates the repository with starter files. The home page's pencil
keeps the in-place editor, but a save is now a commit to profile/README.md
with the admin as the author and web.home.intro in the audit log, instead of a
row in users.db.

The rest of the landing page stays in the shape it had: instance_name as the
heading, the introduction card, then the repository grid beside the Latest
rail. Moving a configurable page layout into a template system was tried and
dropped: this is fixed files, not a templating surface.

This replaces the pending introduction-store change, which is closed.

forge/config/config.go +11−7

@@ -132,12 +132,12 @@ type Config struct {
132 132 // instance grant and only repository defaults apply. The role applies to
133 133 // public repositories; "admin" is refused for self-registration.
134 134 OpenRegistrationRole string `toml:"open_registration_role"`
135 // InstanceName is what the forge calls itself in the landing page heading and
136 // the page title. Empty uses "Vole".
135 // InstanceName is the heading on the landing page. Empty uses "Vole".
137 136 InstanceName string `toml:"instance_name"`
138 // InstanceTagline is the one line under the name on the landing page. Empty
139 // uses a neutral description of what the instance is for.
140 InstanceTagline string `toml:"instance_tagline"`
137 // InstanceRepo names the repository whose tree customizes this instance:
138 // profile/README.md, profile/custom.css, profile/favicon.svg and assets/.
139 // Empty disables the customization entirely.
140 InstanceRepo string `toml:"instance_repo"`
141 141 // PublicURL is where this instance is reachable from a browser:
142 142 // "https://forge.example.com" behind a proxy, normally. It is optional for a
143 143 // read-only instance; browser login is enabled only when it is an https URL,
@@ -189,6 +189,7 @@ func defaults() *Config {
189 189 PagesProcs: 4,
190 190 PagesCacheBytes: 32 << 20, // 32 MiB holds several 10k-file sites
191 191 OpenRegistrationRole: "none",
192 InstanceRepo: "vole-instance",
192 193 }
193 194 }
194 195
@@ -342,9 +343,12 @@ ssh_addr = "127.0.0.1:2222"
342 343 # print the page for something it just created. Trailing slash is ignored.
343 344 # public_url = "https://forge.example.com"
344 345
345 # What the landing page calls this forge. Empty uses "Vole" and a neutral line.
346 # What the home page calls this forge. Empty uses "Vole".
346 347 # instance_name = "Acme Forge"
347 # instance_tagline = "Code, issues, change requests, and CI for the Acme team."
348
349 # The repository whose tree customizes this instance: profile/README.md,
350 # profile/custom.css, profile/favicon.svg, and assets/. Empty disables it.
351 # instance_repo = "vole-instance"
348 352
349 353 # Development only: sign loopback browser requests in as this account. Refused
350 354 # unless http_addr is a loopback address. Never enable this on a shared instance.