# Add stream close coverage for pack push paths

`74213a2`→[main](/content/gh/entireio/git-sync/commits/main/index.html)·Soph·3mo ago·2 files·+120 added/-1 removed

## Sessions

6bda93bfe6b6View transcript

[?\
Can you take a look at the go code (wasm) in /Users/soph/Work/entire/devenv/entire-io-worktree1 based a bit on that I wonder if something like this can be build:Codex·GPT-5.4·1 step](/content/gh/entireio/git-sync/session/019d6d29-8cf7-7fe3-adc9-8c3e4d9d5603#timeline-6bda93bfe6b6/index.html)

## Changes

2

- docs
    
  - Mrewrite-issue-list.md+2/-1

- internal/gitproto
    
  - Apush_test.go+118

```
155 unmodified lines

156
157
158
159
159
160
161
162
163

155 unmodified lines

- Failing batch pushes must not leak HTTP response bodies.

Current rewrite note:
- Ownership of stream lifecycle is clearer than on `main`, but this still wants an explicit close-audit and tests around failing push paths.
- Ownership of stream lifecycle is clearer than on `main`, and the rewrite now has direct tests for key pack-stream close behavior on success and error paths.
- This still wants a fuller close-audit around all strategy-level failure paths before it should be considered fully done.

### 6. Protocol v2 tag fetches request `include-tag` without capability gating
```

Mdocs/rewrite-issue-list.md+2/-1

```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

package gitproto

import (
	"bytes"
	"context"
	"errors"
	"io"
	"testing"

"github.com/go-git/go-git/v5/plumbing/protocol/packp"
	"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
	"github.com/go-git/go-git/v5/plumbing/transport"
)

func TestOpenV2PackStreamCloseClosesBody(t *testing.T) {
	body := &trackingReadCloser{
		ReadCloser: io.NopCloser(bytes.NewBufferString(
			FormatPktLine("packfile\n"),
		)),
	}

rc, err := openV2PackStream(body)
	if err != nil {
		t.Fatalf("openV2PackStream: %v", err)
	}
	if err := rc.Close(); err != nil {
		t.Fatalf("close pack stream: %v", err)
	}
	if !body.closed {
		t.Fatal("expected underlying body to be closed")
	}
}

func TestPushPackClosesPackOnSuccess(t *testing.T) {
	pack := &trackingReadCloser{ReadCloser: io.NopCloser(bytes.NewBufferString("PACK"))}
	conn := &Conn{
		Transport: fakeTransport{receivePackSession: &fakeReceivePackSession{}},
	}
	adv := packp.NewAdvRefs()
	adv.Capabilities = capability.NewList()

err := PushPack(context.Background(), conn, adv, []PushCommand{{
		Name: "refs/heads/main",
	}}, pack, false)
	if err != nil {
		t.Fatalf("PushPack returned error: %v", err)
	}
	if !pack.closed {
		t.Fatal("expected pack to be closed on success")
	}
}

func TestPushPackClosesPackOnReceivePackError(t *testing.T) {
	pack := &trackingReadCloser{ReadCloser: io.NopCloser(bytes.NewBufferString("PACK"))}
	conn := &Conn{
		Transport: fakeTransport{receivePackSession: &fakeReceivePackSession{
			err: errors.New("receive-pack failed"),
		}},
	}
	adv := packp.NewAdvRefs()
	adv.Capabilities = capability.NewList()

err := PushPack(context.Background(), conn, adv, []PushCommand{{
		Name: "refs/heads/main",
	}}, pack, false)
	if err == nil {
		t.Fatal("expected PushPack to return an error")
	}
	if !pack.closed {
		t.Fatal("expected pack to be closed on error")
	}
}

type trackingReadCloser struct {
	io.ReadCloser
	closed bool
}

func (r *trackingReadCloser) Close() error {
	r.closed = true
	if r.ReadCloser != nil {
		return r.ReadCloser.Close()
	}
	return nil
}

type fakeTransport struct {
	receivePackSession transport.ReceivePackSession
}

func (t fakeTransport) NewUploadPackSession(*transport.Endpoint, transport.AuthMethod) (transport.UploadPackSession, error) {
	return nil, errors.New("not implemented")
}

func (t fakeTransport) NewReceivePackSession(*transport.Endpoint, transport.AuthMethod) (transport.ReceivePackSession, error) {
	return t.receivePackSession, nil
}

type fakeReceivePackSession struct {
	err error
}

func (s *fakeReceivePackSession) AdvertisedReferences() (*packp.AdvRefs, error) {
	return packp.NewAdvRefs(), nil
}

func (s *fakeReceivePackSession) AdvertisedReferencesContext(context.Context) (*packp.AdvRefs, error) {
	return s.AdvertisedReferences()
}

func (s *fakeReceivePackSession) ReceivePack(context.Context, *packp.ReferenceUpdateRequest) (*packp.ReportStatus, error) {
	if s.err != nil {
		return nil, s.err
	}
	return nil, nil
}

func (s *fakeReceivePackSession) Close() error { return nil }
