Monorepo for Tangled tangled.org

knot2: classify upload-pack requests by the command line, not the first line #4599

Open mads.havmand.eu
targeting master from mads.havmand.eu/core:upload-pack-v2-detect
Open opened by and assigned to mads.havmand.eu
targeting master from mads.havmand.eu/core:upload-pack-v2-detect

Summary #

The upload-pack request classifier only recognized a request as protocol v2 when the first pkt-line started with command=. Some clients send object-format=sha256 ahead of command=fetch (observed on Google's Go module proxy fetch worker, git/2.30.2). The knot then answered the negotiated v2 fetch in v0 style: a NAK pkt followed by a raw, unframed pack.

A v2 client with sideband-all reads every pkt payload as a sideband band. The N of NAK is 0x4e = 78, which surfaces as:

fatal: fetch-pack: protocol error: bad band #78
fatal: remote-curl: bad line length character: PACK

and the raw pack bytes land where a pkt-line header belongs. No byte is corrupt anywhere; the framing is wrong for the negotiated protocol.

PR fixes issue #774

Evidence #

Captured on a live knot while a Go module proxy fetch worker reproduced the failure (go get go.daevix.com/daevix/cmd/dvx@v0.0.1-rc4):

  • The failing response starts 0008NAK.PACK\x00\x00\x00\x02...: a NAK pkt with raw pack bytes outside any band, directly after it.
  • Every response to a client that sends command= first starts 000e\x01packfile and validates fully.
  • The captured request body has object-format=sha256 as its first line, command=fetch as its second.
  • 25+ fetches bypassing the Go module proxy and 10 direct clones all passed, because those clients send command= first.

Fix #

Scan the request for the command= line wherever it appears, and dispatch on the found line. A v0 request never contains a command= line, so v0 detection is unaffected.

Test #

a_v2_capability_before_the_command_still_gets_a_v2_response reproduces the worker's exact request shape and asserts the response uses v2 band framing. It fails with a v0-style response before the fix and passes after.

Relation to the shallow fix #

Together with #2262 (pack objects behind client shallow boundaries), this closes out #769: the shallow bug broke every GOPROXY=direct fetch of tagged versions, and this bug broke every fetch that went through the Go module proxy's checksum verification. Both were observed as the same bad band #78 / bad line length character: PACK failure on go get go.daevix.com/... vanity imports. Deployed together on a production knot, go get through the default proxy chain succeeds and sum.golang.org records a positive checksum for the module.

Commits 1

knot2: classify upload-pack requests by the command line, not the first line