SSH transport for git: serve clone/fetch and push over ssh:// #1
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub#1
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Motivation
HTTP is walhub's only git transport today. Every mainstream git host also serves git over SSH, and many CI robots and desktop tools expect it (
git clone git@host:owner/repo.git). We need both standard directions:git-upload-pack): clone and fetchgit-receive-pack): pushPrior art (Gitea / Forgejo)
Both Gitea and Forgejo do this well in Go and their shape is a strong hint:
modules/ssh/ssh.go: agolang.org/x/crypto/sshserver; the session handler receives the command string (git-upload-pack '/owner/repo.git'), parses it with a shell-word splitter, and dispatches to an internalservpath.git-upload-pack,git-receive-pack,git-upload-archive; interactive shells/PTY requests are refused.GIT_PROTOCOLenv (SSHSendEnv) is honored and forwarded so protocol v2 works over SSH.Design sketch for walhub
internal/sshdbuilt ongolang.org/x/crypto/ssh(needs a Law 1 amendment inAGENTS.md+ the doc decisions ledger; hand-rolling SSH is a non-starter). It defines a small consumer-sideTransportinterface thatinternal/serverimplements, so the SSH path reuses the exact same git pipeline as HTTP (sync → upload-pack; parse → ingest → connectivity → publish → report).uploadPackandreceivePackLocal(they already only write bytes) and have both HTTP handlers and the SSH dispatcher call them.ssh.ParseAuthorizedKey; the matched key's principal gets write/admin from its entry, and receive-pack requireswrite(same rule as the HTTP route). Keys are a credential class of their own, like static tokens.verb '<owner/repo[.git]>'with option-prefixed argv rejected (the classic SSH option-injection guard); repo paths go throughValidateRepoPath; placement/drain gates apply before any git work.GIT_PROTOCOL=version=2passthrough for v2 negotiation.Testing
.gitsuffix, injection attempts)git cloneandgit pushoverssh://127.0.0.1:<random>against the in-process server with a generated client key andGIT_SSH_COMMAND(both directions, protocol v2)Out of scope (for this first cut)
git-upload-archiveand LFS-over-SSH (git-lfs-authenticate)