Changelog
1.2.4
- The add-repo panel now spans the full content width (matching the repo list and stat row below/above it) instead of being capped at 480px next to empty space.
- Redesigned the login page as a centered card with the gitfed logo and tagline, instead of a bare form dropped at the top of the page.
1.2.3
- Replaced the dashboard's two side-by-side "New repo" / "Import from URL" cards (uneven heights, visually unbalanced) with a single "+ Add a repo" button opening one panel with two tabs, reusing the same toggle mechanism as the repo page's HTTPS/SSH switch.
- Fixed
.gf-page-headvertically centering its title against tall sibling content instead of pinning it to the top — visible on the dashboard once the add-repo panel is open.
1.2.2
- The "New repo" form now shows the same locked
username/prefix as the one-shot import form, instead of a bare field with a placeholder example.
1.2.1
- Reworked the one-shot import form: source URL first, repo name shown as a locked
username/prefix plus an editable, auto-filled suffix, instead of one plain text field with a placeholder example. - Fixed a real bug found while testing the above:
ImportReposhared the admin RPC client's flat 5-second timeout with every other (local, near-instant) admin call, so an actual network clone could fail with a spurious i/o timeout mid-transfer even though it was still running fine server-side. It now gets its own deadline matching the server-side clone timeout.
1.2.0
- One-shot repo import: paste a source repository's HTTPS URL in the dashboard and gitfed clones it once (
git clone --mirror, then detaches theoriginremote so it never re-fetches on its own) into a new repo under your own namespace — no separate admin tooling needed. Restricted tohttps://URLs with no embedded credentials, resolving to a public address (same anti-SSRF DNS check as federation discovery). Continuous mirroring is explicitly out of scope — see ROADMAP.md §3. - Simplified the homepage's changelog preview from a rendered 3-entry list down to a single "Full changelog" button — the full-list version shipped in 1.1.1 turned out to be more than needed.
1.1.1
- The homepage now previews the 3 most recent changelog entries, with a link to the full changelog — previously the only way to see what shipped was navigating to
/changelogdirectly.
1.1.0
- Public profile pages:
/u/{username}shows a Markdown bio (editable from Settings → Profile), the user's public repos, join date, and recent activity merged across those repos. Repo owners are now clickable links to their profile wherever they're shown (repo page,/explore) when the owner is a local account.
1.0.4
- Reverted
gitfed-tui -create-repofrom 1.0.3 — it was a product change made as a side effect of building an unrelated Claude Code skill, without being asked for.-set-public/-set-private(added separately, for the actual V1 launch request) stay.
1.0.3
gitfed-tui -create-repo <owner/repo> -owner <username> [-public]: creates a repo non-interactively, same rationale as-set-public/-set-private— scriptable overkubectl execwithout driving the TUI's keystrokes. Built for a Claude Code skill that publishes a local repo to a running instance end-to-end.
1.0.2
- The clone box now spans the full content width instead of stopping at 560px, matching the file list and every other card on the repo page.
1.0.1
- Fixed the repo page's action bar breaking on real (long) domains: the HTTPS and SSH clone boxes were each their own
flex: 1box competing for room in the same row as the branch/Commits/Merge requests/Settings buttons, so a real hostname wrapped mid-URL instead of eliding cleanly. Regrouped into one compact clone box with an HTTPS/SSH toggle (reusing the same tab-switching JS as the settings page), separate from the row of action buttons. Found on the live instance right after making its own repo public — the first time a public, non-empty, admin-visible repo with a real long domain had ever actually rendered this bar.
1.0.0
First stable release. Federated SSH-certificate identity, per-repo/per-role ACLs, a self-service web UI (repo browser, commit history and detail, merge requests with review and a real server-side merge, pinned repos, federated notifications), anonymous read-only HTTPS clone for public repos, and a documented backup/restore procedure — see README.md for the full picture and ROADMAP.md for what was deliberately left out and why.
Also adds gitfed-tui -set-public <repo> / -set-private <repo>: a non-interactive way to flip a repo's visibility over kubectl exec, without driving the interactive TUI's keystrokes against a live instance.
0.10.3
- A file path outside the repo tree (e.g.
?path=../../../etc/passwd) returned a raw 500 instead of the usual 404 — git itself already rejects it (relative path syntax can't be used outside working tree), so nothing was ever exposed, but gitfed didn't recognize that error as "not found" like it does every other one. Found while re-checking the older file-browsing code for the same bug class as 0.10.1's fix.
0.10.2
- Merge request title/description/comment length limits are now enforced server-side, not just as HTML
maxlengthattributes a direct POST trivially bypasses. Found during the same audit as 0.10.1's fix; full writeup indocs/security/AUDIT-2026-07-29b.md.
0.10.1
- Security fix (critical): argument injection via commit hashes and branch names. Every place that passed a hash or branch name as the last argument to a
gitsubprocess (ShowCommit,CommitDiff,BranchDiff,CheckMergeable,MergeBranches, the merge-request worktree/merge machinery) trusted it as a plain revision — but git ref names can start with-(client-sidegit branch/checkout -bblock it, a rawupdate-refor push doesn't), so a crafted name like--output=/some/pathgot parsed as git's own flag instead. Confirmed exploitable unauthenticated, on any public repo, via/repo-commit/{repo}?hash=--output=<path>— no push access needed at all — to makegitwrite to an arbitrary file path gitfed-server can reach, which is a path to planting a malicious git hook and getting code execution on the next push. Fixed by adding--end-of-optionsbefore every such argument everywhere ininternal/gitexec, with a regression test that reproduces the exact exploit and asserts no file gets written. - Fixed a data-integrity bug found while auditing the above: closing a merge request didn't check its current status, so closing an already-merged MR silently overwrote its record to "closed without merging" — the merge commit stayed real in the branch, but gitfed's own history of it lied.
CloseMergeRequestis now a no-op on anything that isn't still open.
0.10.0
- Added merge requests: propose merging one branch into another within a repo, with a live diff (always computed from the branches' current tips, never a stale snapshot), a discussion thread, and a one-click merge that creates a real merge commit. Conflicts are detected up front and block the merge with the specific files listed, instead of silently failing — resolve locally, push, and the merge request picks up the new state automatically. Merging never touches git's wire protocol: it's an authenticated web action gated by the same write-access check as a
git push, executed server-side in a throwaway worktree so it can never corrupt a real branch ref, with an atomic compare-and-swap update so a concurrent push can't be silently discarded.
0.9.8
- Added
deploy/backup.sh: snapshots the wholegitfed-dataPVC (bbolt store, CA key, host key, bare repos) to a timestamped tarball downloaded off the VPS, with automatic pruning. Previously the only documented backup procedure was "copy the whole PVC by hand." Restore procedure and a throwawaydeploy/k8s/restore-pod.yamldocumented indeploy/k8s/README.md.
0.9.7
- Capitalized "Gitfed" as a proper noun throughout the nav and UI copy (was lowercase "gitfed" everywhere). Also fixed the page
<title>showing the brand name twice on the landing and security pages.
0.9.6
- Commits in the history view are now clickable: each opens a detail page with the full commit message, author/date/hash/parent, the list of changed files (with a status badge and +/− counts), and a full colored diff. Very large diffs are capped at 4000 lines with a notice instead of being loaded in full.
0.9.5
- The repo page no longer dumps the full LICENSE text inline — it's a lot of legal boilerplate pushing the actual content (README, files) further down. Now shows a compact "View file" button linking to the license blob instead.
0.9.4
- Redesigned the Explorer page: a name filter, a topic-chip row (click to filter, click again to clear), and repo cards matching the rest of the app's visual language instead of a plain table. Proper empty state when a filter matches nothing.
0.9.3
- Fixed inconsistent card widths on repo settings and account settings: forms (visibility/topics, grant collaborator, add SSH key, change password) were capped at 480px while list cards next to them weren't, making the layout look jagged. Only the login form keeps the narrow width now.
- Renamed "Dashboard"/"Tableau de bord" to "My repos"/"Mes repos" in the nav.
0.9.2
Follow-up security audit on everything added since the pre-prod one (docs/security/AUDIT-2026-07-29.md) — the anonymous HTTPS clone, federated notifications, pinned repos. No critical findings; three real gaps fixed:
- The anonymous git-clone endpoints had no rate limiting at all (unlike login/notify) — now capped at 60 requests/minute/IP.
- Notifications had no per-recipient cap — any instance could bloat a real user's storage with fake claims; now capped at 200, oldest evicted first.
- A notification's recipient username was never checked to actually exist locally before being stored.
Also: git's stderr was being silently discarded on the HTTP clone endpoints instead of logged, and the "this is informational only" disclaimer on /notifications now explicitly says the content isn't verified, only the sender's signature.
0.9.1
- Settings and repo-settings visually brought up to date with the rest of the app: icons on the settings tabs, a real profile card, collaborators shown as icon+role rows instead of a bare table (with a shield for the owner, a globe for federated collaborators), and a visually distinct danger zone.
- Added confirmation prompts to two destructive actions that didn't have one: revoking a collaborator, and removing an SSH key (the latter warns if it might be your only one).
0.9.0
- Pinned remote repos: bookmark a repo on another instance from your dashboard — works instantly for public repos (no login needed there), and just gives a link for a private one you already have git access to.
- Federated notifications: when someone grants you access to a repo on their instance, you now get a notification on your own instance (a bell in the nav) telling you about it — signed by the granting instance's CA and verified against a fresh fetch of its public key, with no persisted trust relationship required since it's purely advisory (accepting one only pins the link; it never grants access by itself). Rate-limited per source IP.
- Commit history: a new "Commits" view on every repo page (author, date, subject, short hash).
- The HTTPS clone URL on a repo page is now explicitly labeled "read-only".
- New
THIRD_PARTY_LICENSES.mdlisting every Go dependency and its license, split out of the main README.
0.8.0
- Public repos can now be cloned anonymously over HTTPS —
git clone https://<domain>/<owner>/<repo>.gitworks with no account, no SSH key, nothing. Strictly read-only: there is nogit-receive-packroute over HTTP,repo.Publicis re-checked on every request, and private/nonexistent repos 404 identically. Push still only ever works over SSH. The repo page shows both the HTTPS and SSH clone URLs for public repos now.
0.7.1
- Fixed relative links inside rendered README/LICENSE/markdown files (e.g.
docs/HOW_IT_WORKS.md,README.fr.md) — they were left as plain relative hrefs, which the browser resolved against the current page URL instead of the repo's own file tree, so they 404'd. They now resolve through gitfed's own file browser, the same way GitHub/GitLab resolve relative README links.
0.7.0
Pre-production security hardening, from a full defensive audit (docs/security/AUDIT.md, fix plan in docs/security/FIX_PLAN.md). Nothing critical was found — this closes the gaps expected before putting real accounts on the instance:
- Login rate limiting (per account and per IP) on the web login, with generic error messages either way.
- Anti-SSRF on federation discovery: hostname-only validation, private/loopback/link-local/CGNAT IP blocking enforced at dial time (closes DNS-rebinding), 1 MiB response cap.
- Strict
Content-Security-Policyand the standard hardening headers (X-Frame-Options,X-Content-Type-Options,Referrer-Policy, HSTS); same-origin check on all state-changing POSTs as CSRF defense-in-depth. - Certificate revocation: deleting a user or removing an SSH key now immediately blocks any certificate still outstanding for it, instead of waiting out its TTL. Default certificate lifetime cut from 48h to 24h.
gitfed-renew-certnow requires-host-key(or explicit-insecure) instead of silently skipping host-key verification.- Constant-time password check (no more timing difference between "wrong password" and "no such user").
- Web sessions: 30-day TTL cut to 7 days, plus an hourly sweep of expired sessions.
- bcrypt cost 10 → 12.
- Self-service repo creation is now namespaced to the creator and capped at 100 repos/user.
- HTTP servers (web + well-known) now have read/write/idle timeouts.
- Kubernetes: read-only root filesystem, all capabilities dropped,
seccompProfile: RuntimeDefault, and an egressNetworkPolicyscoping outbound traffic away from private ranges.
0.6.0
- Multi-language UI: French and English, with a switcher in the nav (persisted in a cookie, otherwise detected from the browser's
Accept-Language). Every existing page was translated, not just new ones. - New home page at
/explaining what gitfed is for — self-hosted ownership, federation, control — instead of jumping straight to the repo browser, which moved to/explore. - New
/securitypage: how gitfed is actually secured, in plain language, with diagrams (SSH-only transport, certificate issuance, federation trust states, web/git isolation). - Replaced every emoji (📁 📄 ⎇ ⧉ ⚙ 🛡 ↪ ✓) with a small SVG line-icon set drawn in the same square-cornered style as the logo, via a single sprite shared across pages.
0.5.3
- Reverted the repo page to its normal reading-width column (980px) — only the file table's rows needed to stretch, not the whole page, which is what 0.5.2 actually fixed.
0.5.2
- Fixed the file table's rows not actually spanning the page width — a generic table style meant for the admin lists (horizontal scroll on narrow screens) was overriding the file table's layout and shrink-wrapping its rows.
0.5.1
- README.md added, documenting the project, how the certificate-based federation model works, and how to deploy it.
- Fixed the actual
bastien-mrq/gitfedrepo missing a README on gitfed itself — the instance's git remote had fallen 13 commits behind local, never pushed since the very first commit. - Repo file browser page (file table + rendered README/LICENSE) is now full-width instead of capped at the usual reading column; every other page is unchanged.
0.5.0
- Profile (avatar + username) moved to a dropdown at the right of the nav — Settings, Admin (if admin) and Log out live there now instead of cluttering the main nav links.
- Dashboard: a repos/public/shared-with-you stat strip, and the repo list is icon+role+topics rows instead of a bare table; creating a repo is a disclosure ("+ New repo") instead of an always-open form.
- Settings: split into Profile / SSH keys / Password tabs. Tab selection survives the redirect after adding/removing a key or changing your password.
- Admin: the index page is stat cards with real counts (users by role, trust store total/pending, audit event count) and a 5-event recent-activity preview, instead of a bare list of links.
0.4.0
- Repo page rebuilt GitLab-style: the file browser and the README/LICENSE view are one page now — the file table sits directly above the rendered README, no separate "browse files" click. Directories only show README/LICENSE/tags at the repo root, matching how GitLab scopes it.
- Repo page also gained a branch label (⎇ main), a clone URL with a copy-to-clipboard button, and a real empty-repo state (clone command instead of a blank page) for repos with no commits yet.
- Navbar redesigned: search (repos by name/topic,
⌘K/Ctrl+Kto focus it), a user avatar, and a proper responsive collapse to a hamburger menu below ~720px instead of the old bar just running out of room. - New
/searchpage. - Refined the color palette (a fuller token system — canvas/surface/border/text-dim/accent, etc.) and made every existing table horizontally scrollable instead of overflowing on narrow viewports.
0.3.0
- File browser (
browse fileson any repo): breadcrumbed directory listing, markdown rendered inline, anything else shown as plain text, binary files detected and not dumped. - Rendered README/LICENSE pages got real styling — tables, blockquotes, task-list checkboxes, code blocks — instead of bare unstyled HTML.
- Fixed: repos pushed under a branch name that didn't match the bare repo's default
HEAD(e.g.mainvsmaster) silently looked empty everywhere — browsing, README rendering, tags. Every freshly pushed repo hit this. Bare repos now defaultHEADtomainat creation, and reads fall back to a repo's sole branch whenHEADdoesn't resolve, so already-affected repos self-heal with no migration. - Fixed: errors crossing the admin RPC socket lost their identity (a fresh
errors.Newnever equals a sentinel like "not found," even with identical text), which 500'd the repo settings page for any repo with no collaborators yet. - Logo: the "Branch Blocks" mark (a git fork drawn as three square-cornered rectangles) in the header and as a light/dark-aware favicon.
- Version tracking and this changelog.
0.2.0
- Real username/password login for the web UI, with server-side sessions (not just an admin tool behind
kubectl port-forwardanymore). - Self-service: manage your own SSH keys, create and configure your own repos (public/private, topics, collaborators) without needing an instance admin.
- Admin section (user management, trust store, audit log) gated by an admin role on your account instead of being the only thing the web UI could do.
- Merged the public repo browser into the same app as the admin UI — one login, scoped by what each route actually needs.
0.1.0
- Initial implementation: SSH server with a local CA, certificate-based cross-instance identity, ACL model with public/private repos, federation trust store with rate limiting, audit log, admin TUI, admin web UI, public read-only repo browser, and Kubernetes deployment manifests.