Skip to content

Commit 643feb9

Browse files
committed
Remove go-getter from GetContent
Remove the go-getter dependency from bundlereader and replace its use with go-git for git sources and stdlib HTTP for HTTP archive extraction. CA bundles augment the system pool rather than replacing it; go-git creates an isolated transport per clone so concurrent clones with different CAs need no mutex. SCP-style SSH sources accept any username, and forced-scheme prefixes (git::, ssh::) are normalised to proper URLs. Source shorthands cover GitHub, GitLab, and Bitbucket. HTTP archives (tar.gz, tar.bz2, tar.zst, tar, gz, bz2, zst, zip) are extracted inline; ?checksum=<type>:<hex> verifies the body via a TeeReader; ?archive= overrides extension detection. Symlink and path traversal in tar and zip archives are rejected. Error messages redact any embedded credentials in clone URLs.
1 parent c4bbb11 commit 643feb9

20 files changed

Lines changed: 2040 additions & 431 deletions

e2e/single-cluster/go_getter_custom_ca_test.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,12 @@ import (
2121
"sigs.k8s.io/yaml"
2222
)
2323

24-
// Those tests are specifically targeting one feature of go-getter, namely cloning of git
25-
// repositories using HTTPS. That is, because TLS certificates are only used in HTTPS URLs, not if
26-
// SSH keys are used to clone those repositories. Since go-getter shells out to the `git` CLI for
27-
// cloning git repositories, the configuration of TLS certificates or ignoring those needs to be
28-
// configured with `git` typical environment variables. Those are the tests for that implementation.
29-
// For go-getter to be used, the `helm.chart` field in `fleet.yaml` needs to point to a URL that
30-
// tells go-getter to use the git protocol over HTTPS. Such an URL is prefixed with `git::https://`.
31-
// The contents fetched from those repositories are expected to be helm charts.
32-
var _ = Describe("Testing go-getter CA bundles and insecureSkipVerify for cloning git repositories", Label("infra-setup"), func() {
24+
// These tests cover HTTPS cloning of git repositories via the `git::https://` URL prefix in
25+
// `helm.chart`, including TLS certificate configuration (custom CA bundles and InsecureSkipVerify).
26+
// The implementation uses go-git directly; the `git::` prefix is detected by Fleet's source parser
27+
// and dispatched to the go-git–based fetcher. The contents fetched from those repositories are
28+
// expected to be helm charts.
29+
var _ = Describe("Testing CA bundles and insecureSkipVerify for cloning git repositories", Label("infra-setup"), func() {
3330
const (
3431
sleeper = "sleeper"
3532
entrypoint = "entrypoint"
@@ -167,7 +164,7 @@ var _ = Describe("Testing go-getter CA bundles and insecureSkipVerify for clonin
167164
tmpAssetDir := path.Join(tmpDir, "entryPoint")
168165
err = os.Mkdir(tmpAssetDir, 0755)
169166
Expect(err).ToNot(HaveOccurred())
170-
url := "git::" + gh.GetInClusterURL(host, HTTPSPort, "repo?ref="+sleeper)
167+
url := "git::" + gh.GetInClusterURL(host, HTTPSPort, "repo//"+sleeper)
171168
err = os.WriteFile(
172169
path.Join(tmpAssetDir, "fleet.yaml"),
173170
fmt.Appendf([]byte{}, "helm:\n chart: %s\n", url),
@@ -185,7 +182,7 @@ var _ = Describe("Testing go-getter CA bundles and insecureSkipVerify for clonin
185182
_, _ = k.Delete("ns", targetNamespace)
186183
})
187184

188-
When("testing custom CA bundles for cloning git with HTTPS using go-getter (fleet.yaml)", func() {
185+
When("testing custom CA bundles for cloning git with HTTPS (fleet.yaml)", func() {
189186
It("should succeed when not configuring any CA", func() {
190187
// Create and apply GitRepo, don't configure CABundle, InsecureSkipTLSVerify,
191188
// helmSecretName, or helmSecretNameForPath in GitRepo.spec which makes it fall back to
@@ -267,7 +264,7 @@ var _ = Describe("Testing go-getter CA bundles and insecureSkipVerify for clonin
267264
})
268265
})
269266

270-
When("testing ignoring insecure certificates for cloning git repositories with HTTPS using go-getter (fleet.yaml)", func() {
267+
When("testing ignoring insecure certificates for cloning git repositories with HTTPS (fleet.yaml)", func() {
271268
It("should succeed when using the incorrect CA bundle provided in GitRepo's CABundle field but setting InsecureSkipTLSVerify to true", func() {
272269
// But it should fail in gitcloner already, not later in fleet apply.
273270
encodedCert := base64.StdEncoding.EncodeToString([]byte("invalid-ca-bundle"))

go.mod

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ require (
2626
github.com/gogits/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
2727
github.com/google/go-cmp v0.7.0
2828
github.com/google/go-containerregistry v0.21.2
29-
github.com/hashicorp/go-getter/v2 v2.2.3
3029
github.com/jpillora/backoff v1.0.0
30+
github.com/klauspost/compress v1.18.5
3131
github.com/onsi/ginkgo/v2 v2.28.1
3232
github.com/onsi/gomega v1.39.0
3333
github.com/opencontainers/go-digest v1.0.0
@@ -82,7 +82,6 @@ require (
8282
github.com/ProtonMail/go-crypto v1.3.0 // indirect
8383
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
8484
github.com/beorn7/perks v1.0.1 // indirect
85-
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
8685
github.com/blang/semver/v4 v4.0.0 // indirect
8786
github.com/cespare/xxhash/v2 v2.3.0 // indirect
8887
github.com/chai2010/gettext-go v1.0.3 // indirect
@@ -135,19 +134,13 @@ require (
135134
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
136135
github.com/gosuri/uitable v0.0.4 // indirect
137136
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
138-
github.com/hashicorp/errwrap v1.1.0 // indirect
139-
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
140-
github.com/hashicorp/go-multierror v1.1.1 // indirect
141-
github.com/hashicorp/go-safetemp v1.0.0 // indirect
142-
github.com/hashicorp/go-version v1.6.0 // indirect
143137
github.com/huandu/xstrings v1.5.0 // indirect
144138
github.com/ianlancetaylor/demangle v0.0.0-20251118225945-96ee0021ea0f // indirect
145139
github.com/inconshreveable/mousetrap v1.1.0 // indirect
146140
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
147141
github.com/jmoiron/sqlx v1.4.0 // indirect
148142
github.com/json-iterator/go v1.1.12 // indirect
149143
github.com/kevinburke/ssh_config v1.2.0 // indirect
150-
github.com/klauspost/compress v1.18.4 // indirect
151144
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
152145
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
153146
github.com/lib/pq v1.10.9 // indirect
@@ -157,7 +150,6 @@ require (
157150
github.com/mattn/go-runewidth v0.0.13 // indirect
158151
github.com/mitchellh/copystructure v1.2.0 // indirect
159152
github.com/mitchellh/go-homedir v1.1.0 // indirect
160-
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
161153
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
162154
github.com/mitchellh/reflectwalk v1.0.2 // indirect
163155
github.com/moby/spdystream v0.5.0 // indirect
@@ -183,7 +175,6 @@ require (
183175
github.com/spf13/pflag v1.0.10 // indirect
184176
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 // indirect
185177
github.com/tetratelabs/wazero v1.11.0 // indirect
186-
github.com/ulikunitz/xz v0.5.15 // indirect
187178
github.com/vbatts/tar-split v0.12.2 // indirect
188179
github.com/x448/float16 v0.8.4 // indirect
189180
github.com/xanzy/ssh-agent v0.3.3 // indirect

go.sum

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
3737
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
3838
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
3939
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
40-
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
41-
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
4240
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
4341
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
4442
github.com/bradleyfalzon/ghinstallation/v2 v2.16.0 h1:B91r9bHtXp/+XRgS5aZm6ZzTdz3ahgJYmkt4xZkgDz8=
@@ -237,19 +235,6 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJr
237235
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
238236
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 h1:X+2YciYSxvMQK0UZ7sg45ZVabVZBeBuvMkmuI2V3Fak=
239237
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII=
240-
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
241-
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
242-
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
243-
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
244-
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
245-
github.com/hashicorp/go-getter/v2 v2.2.3 h1:6CVzhT0KJQHqd9b0pK3xSP0CM/Cv+bVhk+jcaRJ2pGk=
246-
github.com/hashicorp/go-getter/v2 v2.2.3/go.mod h1:hp5Yy0GMQvwWVUmwLs3ygivz1JSLI323hdIE9J9m7TY=
247-
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
248-
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
249-
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
250-
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
251-
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
252-
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
253238
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
254239
github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
255240
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
@@ -272,8 +257,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
272257
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
273258
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
274259
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
275-
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
276-
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
260+
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
261+
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
277262
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
278263
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
279264
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -311,8 +296,6 @@ github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa1
311296
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
312297
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
313298
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
314-
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
315-
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
316299
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
317300
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
318301
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
@@ -438,8 +421,6 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
438421
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
439422
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
440423
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
441-
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
442-
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
443424
github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4=
444425
github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
445426
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=

integrationtests/bundlereader/getcontent_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ var _ = Describe("GetContent fetches files from a git repository", Label("networ
9292
})
9393
})
9494

95+
When("a CA bundle is provided", func() {
96+
It("returns the repository files", func() {
97+
source := fmt.Sprintf("git::%s/%s/%s", httpsBase, utils.GogsUser, repoName)
98+
files, err := bundlereader.GetContent(
99+
context.Background(), GinkgoT().TempDir(), source, "",
100+
bundlereader.Auth{CABundle: gogsCABundle}, false, nil,
101+
)
102+
Expect(err).NotTo(HaveOccurred())
103+
Expect(files).To(HaveKey("README.md"))
104+
})
105+
})
106+
95107
When("no TLS configuration is provided", func() {
96108
It("fails with a certificate error", func() {
97109
source := fmt.Sprintf("git::%s/%s/%s", httpsBase, utils.GogsUser, repoName)
@@ -236,6 +248,47 @@ var _ = Describe("GetContent fetches files from a git repository", Label("networ
236248
Expect(err).NotTo(HaveOccurred())
237249
Expect(files).To(HaveKey("README.md"))
238250
})
251+
252+
It("returns the repository files when a correct known host entry is provided", func() {
253+
privateKey, err := os.ReadFile(tmpKeyFile)
254+
Expect(err).NotTo(HaveOccurred())
255+
256+
knownHost, err := utils.GetGogsKnownHostEntry(context.Background(), container)
257+
Expect(err).NotTo(HaveOccurred())
258+
259+
source := fmt.Sprintf("%s/%s/%s", sshBase, utils.GogsUser, repoName)
260+
Eventually(func() error {
261+
_, err = bundlereader.GetContent(
262+
context.Background(), GinkgoT().TempDir(), source, "",
263+
bundlereader.Auth{SSHPrivateKey: privateKey, SSHKnownHosts: []byte(knownHost)}, false, nil,
264+
)
265+
return err
266+
}, timeout, interval).Should(Succeed())
267+
268+
files, err := bundlereader.GetContent(
269+
context.Background(), GinkgoT().TempDir(), source, "",
270+
bundlereader.Auth{SSHPrivateKey: privateKey, SSHKnownHosts: []byte(knownHost)}, false, nil,
271+
)
272+
Expect(err).NotTo(HaveOccurred())
273+
Expect(files).To(HaveKey("README.md"))
274+
})
275+
276+
It("fails when a wrong known host entry is provided", func() {
277+
privateKey, err := os.ReadFile(tmpKeyFile)
278+
Expect(err).NotTo(HaveOccurred())
279+
280+
// A valid-looking but wrong known_hosts entry: the key is for github.com, not our gogs server.
281+
wrongKnownHost := "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl"
282+
283+
source := fmt.Sprintf("%s/%s/%s", sshBase, utils.GogsUser, repoName)
284+
Eventually(func() error {
285+
_, err = bundlereader.GetContent(
286+
context.Background(), GinkgoT().TempDir(), source, "",
287+
bundlereader.Auth{SSHPrivateKey: privateKey, SSHKnownHosts: []byte(wrongKnownHost)}, false, nil,
288+
)
289+
return err
290+
}, timeout, interval).Should(HaveOccurred())
291+
})
239292
})
240293
})
241294

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package bundlereader_test
2+
3+
import (
4+
"archive/tar"
5+
"bytes"
6+
"compress/gzip"
7+
"context"
8+
"crypto/sha256"
9+
"encoding/hex"
10+
"net/http"
11+
"net/http/httptest"
12+
"path/filepath"
13+
14+
. "github.com/onsi/ginkgo/v2"
15+
. "github.com/onsi/gomega"
16+
17+
"github.com/rancher/fleet/internal/bundlereader"
18+
)
19+
20+
// newTarGz builds a tar.gz archive in memory containing the given files
21+
// (map of relative name → content) and returns the bytes.
22+
func newTarGz(files map[string][]byte) []byte {
23+
var buf bytes.Buffer
24+
gw := gzip.NewWriter(&buf)
25+
tw := tar.NewWriter(gw)
26+
for name, data := range files {
27+
_ = tw.WriteHeader(&tar.Header{
28+
Typeflag: tar.TypeReg,
29+
Name: name,
30+
Size: int64(len(data)),
31+
Mode: 0600,
32+
})
33+
_, _ = tw.Write(data)
34+
}
35+
_ = tw.Close()
36+
_ = gw.Close()
37+
return buf.Bytes()
38+
}
39+
40+
var _ = Describe("GetContent fetches HTTP sources", func() {
41+
var (
42+
srv *httptest.Server
43+
archiveBytes []byte
44+
)
45+
46+
BeforeEach(func() {
47+
archiveBytes = newTarGz(map[string][]byte{
48+
"README.md": []byte("hello"),
49+
"subdir/config.yaml": []byte("key: value"),
50+
})
51+
})
52+
53+
AfterEach(func() {
54+
if srv != nil {
55+
srv.Close()
56+
srv = nil
57+
}
58+
})
59+
60+
When("the URL points to a tar.gz archive", func() {
61+
It("extracts the archive and returns the files", func() {
62+
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
63+
_, _ = w.Write(archiveBytes)
64+
}))
65+
66+
files, err := bundlereader.GetContent(
67+
context.Background(), GinkgoT().TempDir(), srv.URL+"/bundle.tar.gz", "",
68+
bundlereader.Auth{}, false, nil,
69+
)
70+
Expect(err).NotTo(HaveOccurred())
71+
Expect(files).To(HaveKey("README.md"))
72+
Expect(files).To(HaveKey(filepath.Join("subdir", "config.yaml")))
73+
})
74+
})
75+
76+
When("the URL has no recognisable extension but ?archive= is provided", func() {
77+
It("extracts using the override extension", func() {
78+
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
79+
// The server must NOT receive the ?archive= parameter.
80+
Expect(r.URL.Query().Get("archive")).To(BeEmpty())
81+
_, _ = w.Write(archiveBytes)
82+
}))
83+
84+
files, err := bundlereader.GetContent(
85+
context.Background(), GinkgoT().TempDir(), srv.URL+"/download?archive=tar.gz", "",
86+
bundlereader.Auth{}, false, nil,
87+
)
88+
Expect(err).NotTo(HaveOccurred())
89+
Expect(files).To(HaveKey("README.md"))
90+
})
91+
})
92+
93+
When("a correct ?checksum= is provided", func() {
94+
It("succeeds when the hash matches", func() {
95+
h := sha256.New()
96+
h.Write(archiveBytes)
97+
hexHash := hex.EncodeToString(h.Sum(nil))
98+
99+
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
100+
// The server must NOT receive the ?checksum= parameter.
101+
Expect(r.URL.Query().Get("checksum")).To(BeEmpty())
102+
_, _ = w.Write(archiveBytes)
103+
}))
104+
105+
_, err := bundlereader.GetContent(
106+
context.Background(), GinkgoT().TempDir(),
107+
srv.URL+"/bundle.tar.gz?checksum=sha256:"+hexHash, "",
108+
bundlereader.Auth{}, false, nil,
109+
)
110+
Expect(err).NotTo(HaveOccurred())
111+
})
112+
113+
It("fails when the hash does not match", func() {
114+
wrongHash := "0000000000000000000000000000000000000000000000000000000000000000"
115+
116+
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
117+
_, _ = w.Write(archiveBytes)
118+
}))
119+
120+
_, err := bundlereader.GetContent(
121+
context.Background(), GinkgoT().TempDir(),
122+
srv.URL+"/bundle.tar.gz?checksum=sha256:"+wrongHash, "",
123+
bundlereader.Auth{}, false, nil,
124+
)
125+
Expect(err).To(HaveOccurred())
126+
Expect(err.Error()).To(ContainSubstring("checksum mismatch"))
127+
})
128+
})
129+
130+
When("the URL points to a plain file", func() {
131+
It("writes the file under its URL base name", func() {
132+
content := []byte("plain content")
133+
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
134+
_, _ = w.Write(content)
135+
}))
136+
137+
files, err := bundlereader.GetContent(
138+
context.Background(), GinkgoT().TempDir(), srv.URL+"/data.txt", "",
139+
bundlereader.Auth{}, false, nil,
140+
)
141+
Expect(err).NotTo(HaveOccurred())
142+
Expect(files).To(HaveKey("data.txt"))
143+
Expect(files["data.txt"]).To(Equal(content))
144+
})
145+
})
146+
})

0 commit comments

Comments
 (0)