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

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

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

#24

Add vole change merge, over an SSH verb

merged · by keenan 13d ago · merged into main at b14a7819 by keenan 13d ago

keenan opened this 13d ago

Second half of #01M5XF4XWHVMMCQEYENA8X32GK. The landing operation is on main (#01M5XFEHF38KDXD21TZVJS15GS); this adds vole change merge <id>, which is the part the CLI could not do from a clone.

Why this needs a transport

Landing is allowed or refused by three things that live in the instance and nowhere in a working tree: the repository’s ACL, the approvals filed against the request, and the run results. The CLI already commits metadata by pushing, but a merge has to move refs/heads/<base> — a push of the base branch is precisely what this feature replaces, and doing it from the client would put the decision on the wrong side.

So the client asks the server over the key it already pushes with (vole-change-merge <repo-path> <request-id>), next to vole-runner, vole-roster and vole-whoami on the same SSH channel. The server resolves the rules, runs forge/landing.Land, and writes the merge line to the audit log the way a push does.

What changed

  • server/ssh/merge.go: the verb. It takes exactly a repository path and a request id — no shell, no arbitrary arguments — runs the repository path through the same repoName check the git verbs use, requires maintain (CanTriage), builds a landing.Gate from the server’s own open run queue and the ACL’s effective role, and answers one line: merged … into main at <sha>, or the gate’s refusal prefixed vole: so the client can turn it into an error.
  • client/remote.go: MergeChange resolves the remote, refuses a path that does not name a repository, and runs the verb. It reuses RunSSH, so the error path is the one the other verbs already use.
  • cmd/vole/change.go: vole change merge <id>, printed as the server wrote it — the answer names the commit that landed.
  • server/ssh/server.go: the verb is registered, and the “only … are available” refusal lists it.

Verification

vole workflow run verify in the pinned image: gofmt, vet, build, govulncheck (0 reachable), packaging, links, go test -race ./... — all pass.

New tests (server/ssh/merge_test.go), driven over a real SSH session:

  • a read account is refused, and the refusal names the missing capability;
  • a maintainer asking for a request that does not exist gets the landing gate’s own refusal, prefixed vole:, which is what the client turns into an error;
  • the verb is not a shell: a missing argument, a missing id, a name with .., and a command with ; cat /etc/passwd appended all fail without executing anything.

The landing rules themselves are covered by the nine tests in forge/landing from the first half; this change is the wiring, and the wiring is what these tests pin.

Dogfooding note

The instance is running the first half, so the browser button and the merged status are live. The verb needs a restart onto this commit, after which the CLI path can be exercised against the same repository:

vole change merge <id>

Acceptance against the issue

  • vole change merge <id> — lands the approved head and marks the request merged
  • Same gate as the browser button and the pre-receive hook (forge/landing.Check)
  • maintain and above; the author may merge their own approved request
  • Refusals name the reason and change nothing
  • Audited, in the same shape as a merge that arrives by push

Discussion (0)

No discussion yet.