Skip to content

Repositories

For engineers and administrators.

Connect a git repository to a project and the desk links the commits that name an issue, so a fix and the work that describes it are one click apart. Optionally, it keeps a mirror you can browse.

The desk only ever fetches. It never pushes anything anywhere, and nothing is ever pushed into it. It is built for self-hosted bare repositories over SSH: there is no provider integration, no OAuth app and no hosted-service API in it.

How much of the repository to keep

Source code on a support server is a real decision, so it is a choice per repository:

Metadata only: the default : Cloned with no file contents at all. Every commit, tree, branch and tag; not one byte of any file. Commit links and release notes work in full. The browser lists commits and the names of the files each one touched, and says “file contents are not stored on this server” if you ask for a file.

Full mirror : The whole repository, source included, and a complete browser. The interface says plainly what that means: the source is then on this server.

Push only : Nothing is cloned and nothing goes out. The repository’s post-receive hook posts the commits’ details over HTTPS and the desk stores only that. Commits still attach to issues and release notes still work; there is no browser.

Changing the mode does the right thing: what is on disk was kept under the old answer, so it is deleted and re-cloned under the new one. Dropping to push-only also removes the address and the key pair, so no deploy key is left installed anywhere. Commits already attached to issues are never touched.

If a git server refuses to filter, the desk notices, records it, and the project page says the mirror is holding the source after all, and what to do about it.

Connecting one

  1. Address: SSH only: git@host:group/repo.git or ssh://git@host:2222/path. Checked before it is stored: no scheme that would want a password, no leading dash, no shell characters, no path that walks up.
  2. The desk generates a key pair (ed25519) for that repository. Install the public half as a read-only deploy key; its SHA256: fingerprint is shown so you can check it. The private half is encrypted at rest, appears in no API response, and exists on disk only as a mode-0600 file for the length of one git call.
  3. First fetch records the server’s host key. Every fetch after that is strict against it, a server whose key has changed is refused with an explanation. A manager can deliberately forget the recorded key (audited) when a server really was rebuilt.

A host that resolves to a private, loopback or link-local address is refused, unless an administrator ticks “this git server is on an internal address” for that repository. A project manager cannot grant that.

No password is ever accepted, there is no terminal to prompt on, and git never runs through a shell.

Keeping up to date

  • The hook: the repository’s post-receive tells the desk there is something new, and that is all it does. It is signed (timestamp, one-time nonce, HMAC), rate-limited, and every failure answers the same 404. The desk works out what is new from its own mirror rather than believing the hook. The script is generated for you, filled in, ready to paste; it needs curl and openssl on the git server.
  • The sweep: every 15 minutes, anything not fetched for an hour is fetched anyway. So a repository whose hook was never installed, or broke, or was pushed to while the desk was down, still comes up to date. The hook is an optimisation, not a requirement.

Fetching is always on the queue, never in a web request, with a timeout, its own HOME, no system or global git config and no credential helper.

Commits and issues

Any commit whose message names an issue in that repository’s own project (CP-42) is linked to it, carrying the hash, subject, author, date and the branch or tag it arrived on. A reference in another project’s key is ignored rather than guessed at, because two projects can both have a 42.

Nothing is moved or closed by a commit. A commit is evidence that work happened, not a decision about the issue.

Commit subjects, authors and refs are treated as untrusted text: stripped of control characters and terminal escapes, capped, and fenced before they ever reach a model. Nothing from a repository is rendered as markup.

The browser

Held to the project’s own visibility, somebody who cannot see the project cannot see its code by any route. Branches and tags, the file tree, a file with syntax highlighting, the commit list (optionally for one path) and one commit’s diff.

A ref is resolved to a commit hash before anything else runs, so no revision expression reaches git; every path is checked segment by segment. A file over 1 MB or a diff over 512 KB is reported rather than printed, and a binary file is named as one. Everything is read from the mirror on this disk with a timeout, so no web request ever waits on a git server.

Disk

A cap per repository (2 GB) and across all of them (20 GB), both checked before a fetch starts; a first clone that turns out bigger than its cap is removed rather than kept. Disconnecting a repository removes its mirror, and the sweep clears mirrors whose connection has gone.

Repository mirrors are the one thing worth excluding from backups, they are copies of something that exists elsewhere.

Deliberately not built

Pull requests, code review, blame, cross-reference search, and comparing arbitrary refs. Tag comparison exists because release notes need it.