blob: faebf5eb86fe247c6a64d3377851755d63c9b0a1 (plain) (blame)
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#!/bin/sh

# The snapshot page hands a branch back as an archive. One function below
# registers the same checks for every compressed tar format, and each format
# needs the same compressor cgit pipes through on the server, so one missing
# tool skips that format on both grounds at once. Plain tar and zip get checks
# of their own, since cgit runs no compressor for either and unzip shares no
# flags with the rest.

test_description='Verify snapshot'
. ./setup.sh

check_snapshot_headers() {
	head -n 1 tmp | grep "Status: 200 OK" &&
	head -n 2 tmp | grep "^Content-Type: $2$" &&
	head -n 3 tmp | grep "Content-Disposition: inline; filename=.master.$1."
}

check_snapshot_content() {
	ls master/ >output &&
	test_line_count = 5 output &&
	grep "^5$" master/file-5 &&
	test_line_count = 1 master/file-5
}

# Registers the checks for one compressed tar format.
test_tar_snapshot() {
	ext=$1
	type=$2
	tool=$3
	prereq=$4

	test_lazy_prereq $prereq "command -v $tool"

	test_expect_success $prereq "get foo/snapshot/master.$ext" "
		cgit_url 'foo/snapshot/master.$ext' >tmp
	"

	test_expect_success $prereq "check $ext response headers" "
		check_snapshot_headers $ext $type
	"

	test_expect_success $prereq "verify $ext format" "
		strip_headers <tmp >master.$ext &&
		'$tool' -t 'master.$ext'
	"

	test_expect_success $prereq "untar $ext and verify the content" "
		rm -rf master &&
		'$tool' -dc 'master.$ext' | tar -xf - &&
		check_snapshot_content
	"
}

# The uncompressed tar comes straight out of git's archive writer, so tar
# itself both proves the format and unpacks it.
test_expect_success 'get foo/snapshot/master.tar' '
	cgit_url "foo/snapshot/master.tar" >tmp
'

test_expect_success 'check tar response headers' '
	check_snapshot_headers tar application/x-tar
'

test_expect_success 'untar and verify the content' '
	strip_headers <tmp >master.tar &&
	rm -rf master &&
	tar -xf master.tar &&
	check_snapshot_content
'

test_tar_snapshot tar.gz  application/gzip    gzip  GZIP
test_tar_snapshot tar.bz2 application/x-bzip2 bzip2 BZIP2
test_tar_snapshot tar.lz  application/x-lzip  lzip  LZIP
test_tar_snapshot tar.xz  application/x-xz    xz    XZ
test_tar_snapshot tar.zst application/zstd    zstd  ZSTD

test_expect_success 'get foo/snapshot/master.zip' '
	cgit_url "foo/snapshot/master.zip" >tmp
'

test_expect_success 'check zip response headers' '
	check_snapshot_headers zip application/zip
'

test_expect_success 'strip off the header lines' '
	strip_headers <tmp >master.zip
'

test_expect_success UNZIP 'verify zip format' '
	"$GIT_UNZIP" -t master.zip
'

test_expect_success UNZIP 'unzip and verify the content' '
	rm -rf master &&
	"$GIT_UNZIP" master.zip &&
	check_snapshot_content
'

# A tag named v1.0 sheds its v in the snapshot name unless dropping it would
# merge two tags. The first tag below stays a loose ref on purpose, because on
# a case-insensitive filesystem a ref lookup for V1.0 finds the loose v1.0
# file, and deciding by lookups called every fresh tag ambiguous and kept its
# v until git happened to pack the refs.
test_expect_success 'set up a repo with a versioned tag' '
	mkrepo repos/vtags 2 &&
	git -C repos/vtags update-ref refs/tags/v1.0 HEAD &&
	cgitrc_repo vtagsrc vtags snapshots=tar.gz
'

test_expect_success 'a loose v tag still sheds its v in the snapshot name' '
	cgit_rc vtagsrc "url=vtags/refs/" >tmp &&
	grep "vtags-1.0.tar.gz" tmp &&
	! grep "vtags-v1.0.tar.gz" tmp
'

# The second tag goes in only after the first is packed, since two loose files
# differing in case alone cannot coexist on a case-insensitive filesystem.
test_expect_success 'a real case collision keeps the v on both tags' '
	git -C repos/vtags pack-refs --all &&
	git -C repos/vtags update-ref refs/tags/V1.0 HEAD~1 &&
	cgit_rc vtagsrc "url=vtags/refs/" >tmp &&
	grep "vtags-v1.0.tar.gz" tmp &&
	grep "vtags-V1.0.tar.gz" tmp &&
	! grep "vtags-1.0.tar.gz" tmp
'

# A name that is all suffix names no revision, and an empty snapshot-prefix
# gives the members no leading directory rather than a leading slash.
test_expect_success 'a snapshot name with nothing before its suffix is refused' '
	git -C repos/vtags branch v HEAD &&
	sed "s/^snapshots=tar.gz$/snapshots=tar/" vtagsrc >vtagstarrc &&
	cgit_rc vtagstarrc "url=vtags/snapshot/.tar" >tmp &&
	grep "^Status: 404" tmp
'

test_expect_success 'an empty snapshot-prefix puts no slash ahead of the members' '
	{
		cat vtagstarrc &&
		echo "repo.snapshot-prefix="
	} >noprefixrc &&
	cgit_rc noprefixrc "url=vtags/snapshot/vtags.tar&id=master" >tmp &&
	strip_headers <tmp >noprefix.tar &&
	tar -tf noprefix.tar >members &&
	grep "^file-1$" members &&
	! grep "^/" members
'

# A snapshot is named after the last component of the url once its .git
# suffix is gone, so a url of .git alone leaves the ref as the whole name.
test_expect_success 'set up repositories whose urls end in .git' '
	mkrepo repos/dotgit 1 &&
	git -C repos/dotgit tag v1.0 &&
	{
		echo "virtual-root=/" &&
		echo "cache-size=0" &&
		echo "snapshots=tar" &&
		echo "repo.url=.git" &&
		echo "repo.path=$PWD/repos/dotgit/.git" &&
		echo "repo.url=sub/.git" &&
		echo "repo.path=$PWD/repos/dotgit/.git"
	} >dotgitrc
'

test_expect_success 'a url of .git names a snapshot after the ref alone' '
	cgit_rc dotgitrc "url=.git/refs/" >tmp &&
	grep ">v1.0.tar<" tmp &&
	cgit_rc dotgitrc "url=.git/snapshot/v1.0.tar" >tmp &&
	strip_headers <tmp >dotgit.tar &&
	tar -tf dotgit.tar >members &&
	grep "^v1.0/file-1$" members
'

test_expect_success 'a url ending in /.git names a snapshot after its directory' '
	cgit_rc dotgitrc "url=sub/.git/refs/" >tmp &&
	grep ">sub-1.0.tar<" tmp
'

# A server may run cgit with no PATH at all, and the compressor is then looked
# for on the default path execvp searches.
test_expect_success GZIP 'a compressed snapshot is made without a PATH' '
	cgitrc_copy nopathrc &&
	cgit_bin=$(command -v cgit) &&
	(
		unset PATH &&
		CGIT_CONFIG="$PWD/nopathrc" QUERY_STRING="url=foo/snapshot/master.tar.gz" "$cgit_bin" >tmp
	) &&
	grep "^Status: 200" tmp &&
	strip_headers <tmp >nopath.tar.gz &&
	gzip -t nopath.tar.gz
'

# A link offers the snapshot of a tag, and the name on it has to lead back to
# that tag even when a branch is spelled like the tag's stem.
test_expect_success GZIP 'a snapshot name leads to the tag ahead of a branch' '
	git -C repos/vtags update-ref refs/heads/1.0 $(git -C repos/vtags commit-tree -m shadow HEAD^{tree}) &&
	cgit_rc vtagsrc "url=vtags/snapshot/vtags-1.0.tar.gz" >tmp &&
	strip_headers <tmp >tag.tar.gz &&
	test "$(gzip -dc tag.tar.gz | git -C repos/vtags get-tar-commit-id)" = "$(git -C repos/vtags rev-parse refs/tags/v1.0^{commit})"
'

# A signature is a note a pusher stored, held to max-blob-size like any blob.
test_expect_success 'a signature past max-blob-size is refused' '
	big=$(test_seq 1 2000 | git -C repos/vtags hash-object -w --stdin) &&
	git -C repos/vtags notes --ref signatures/tar.gz add -C $big v1.0 &&
	{
		echo "max-blob-size=1" &&
		cat vtagsrc
	} >sigrc &&
	cgit_rc sigrc "url=vtags/snapshot/vtags-1.0.tar.gz.asc" >tmp &&
	grep "^Status: 413" tmp
'

test_expect_success 'a snapshot and its signature are linked as one unit' '
	test_create_repo repos/signed &&
	(
		cd repos/signed &&
		echo one >file &&
		git add file &&
		git commit -m one &&
		git tag one &&
		sig=$(echo signature | git hash-object -w --stdin) &&
		git notes --ref signatures/tar.gz add -C $sig one
	) &&
	cgitrc_repo signedrc signed snapshots=tar.gz &&
	cgit_rc signedrc "url=signed/refs/" >tmp &&
	grep "<span class=.snapshot.><a href=./signed/snapshot/signed-one.tar.gz.>signed-one.tar.gz</a> (<a href=./signed/snapshot/signed-one.tar.gz.asc.>sig</a>)</span>" tmp
'

test_done