Why
Customizing an instance meant editing vole.toml on the host and restarting,
and the packaged service cannot write that file (ProtectSystem=strict). Custom
CSS, a favicon, and static assets had nowhere to live at all. The landing page’s
prose was the one thing an admin could change from the browser, but it was stored
in the instance database rather than with the rest of the customization.
This replaces that with one repository, modelled on GitHub’s .github: fixed
paths read as data. There is no template language, no code execution, and no
trust flag to enable.
Scope
-
forge/instancerepo: reads one commit into an immutable snapshot on a two second timer and swaps it atomically. A request never runs git; a load failure keeps the previous theme; the repository is hidden from the home grid and activity rail. - Fixed paths:
profile/README.md(introduction),profile/private/README.md(signed-in viewers),profile/custom.css,profile/favicon.svg, andassets/served at/static/custom/assets/. Unknown files are ignored. - Markdown goes through the issue sanitiser; assets are an extension whitelist with per-file, total, and count caps. HTML and scripts are not assets. SVG responses carry a sandboxing CSP.
- The home pencil keeps the in-place editor, but a save is now a commit to
profile/README.mdwith the admin as the author andweb.home.introin the audit log. It always writes the public file, even when a private README is what the admin is reading. - Admin → Configuration grows an Instance repository panel: name, loaded commit, last load error, clone URL, recognized paths, and a Create instance repository button that scaffolds the starter files. An existing empty repository is finished rather than rejected.
-
instance_repo(defaultvole-instance, empty disables) andinstance_nameis the heading. Removes the pending introduction-store change (#222, closed in favour of this). - The rest of the landing page keeps its original shape: heading, introduction card, repository grid, Latest rail. The per-card commit line, repository/activity summary, tagline setting, repository search bar, and top-languages block are gone.
Acceptance criteria
- An instance admin can write or clear the introduction without touching the config file or restarting; the save is a commit.
- A visitor sees the sanitized public README, custom CSS, favicon, and assets; a signed-in viewer sees the private README when one exists.
- A non-admin cannot edit, push, or read the instance repository, and it never appears as a project.
- A broken theme keeps the previous snapshot and reports the error only to the admin.
instance_namenames the heading; an unset value showsVole.- No search bar, top-languages block, or tagline on the home page.
Testing
./vole workflow run verify: formatting, vet, build, license/NOTICE,
govulncheck, packaging, deployment files, markdown links, and the full -race
suite pass.
New coverage: forge/instancerepo (fixed paths, ignored files, extension
whitelist, oversized file), server/instance_repo_test.go (public/private
README, CSS/favicon links, asset serving and script rejection, hidden repo,
admin scaffold, editor availability), and the rewritten server/landing_test.go
(editor commits the public README, clears it by deleting the file, audits,
sanitizes, rejects oversized input, admin-only).