Skip to content

Commit d343974

Browse files
committed
Make go-getter use CABundles
Whether defined in secrets from Rancher or in a GitRepo resource, go-getter (`helm.chart` field of `fleet.yaml`) is supposed to use the certificates specified. First the certificate specified in the GitRepo resource, then the ones from Rancher. It also should honor `GitRepo.Spec.insecureSkipTLSVerify` (even when using the Rancher certificates). Refers to #3646
1 parent d0e9668 commit d343974

File tree

7 files changed

+295
-105
lines changed

7 files changed

+295
-105
lines changed

e2e/assets/gitrepo/gitrepo.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,18 @@ spec:
66
repo: {{.Repo}}
77
branch: {{.Branch}}
88
pollingInterval: {{.PollingInterval}}
9+
{{- if .InsecureSkipTLSVerify}}
10+
insecureSkipTLSVerify: {{.InsecureSkipTLSVerify}}
11+
{{- end }}
912
{{- if .TargetNamespace }}
1013
targetNamespace: {{.TargetNamespace}}
1114
{{- end }}
1215
paths:
16+
{{- if .Path }}
17+
- {{.Path}}
18+
{{- else }}
1319
- examples
20+
{{- end }}
21+
{{- if .CABundle}}
22+
caBundle: {{.CABundle}}
23+
{{- end}}

e2e/single-cluster/gitrepo_test.go

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ const (
3131
HTTPSPort = 4343
3232
)
3333

34+
type gitRepoTestValues struct {
35+
Name string
36+
Repo string
37+
Branch string
38+
PollingInterval string
39+
TargetNamespace string
40+
Path string
41+
InsecureSkipTLSVerify bool
42+
CABundle string
43+
}
44+
3445
var _ = Describe("Monitoring Git repos via HTTP for change", Label("infra-setup"), func() {
3546
var (
3647
tmpDir string
@@ -100,18 +111,12 @@ var _ = Describe("Monitoring Git repos via HTTP for change", Label("infra-setup"
100111
})
101112

102113
JustBeforeEach(func() {
103-
err := testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), struct {
104-
Name string
105-
Repo string
106-
Branch string
107-
PollingInterval string
108-
TargetNamespace string
109-
}{
110-
gitrepoName,
111-
inClusterRepoURL,
112-
gh.Branch,
113-
"15s", // default
114-
targetNamespace, // to avoid conflicts with other tests
114+
err := testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), gitRepoTestValues{
115+
Name: gitrepoName,
116+
Repo: inClusterRepoURL,
117+
Branch: gh.Branch,
118+
PollingInterval: "15s", // default
119+
TargetNamespace: targetNamespace, // to avoid conflicts with other tests
115120
})
116121
Expect(err).ToNot(HaveOccurred())
117122

@@ -157,18 +162,12 @@ var _ = Describe("Monitoring Git repos via HTTP for change", Label("infra-setup"
157162
})
158163

159164
JustBeforeEach(func() {
160-
err := testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), struct {
161-
Name string
162-
Repo string
163-
Branch string
164-
PollingInterval string
165-
TargetNamespace string
166-
}{
167-
gitrepoName,
168-
inClusterRepoURL,
169-
gh.Branch,
170-
"15s", // default
171-
targetNamespace, // to avoid conflicts with other tests
165+
err := testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), gitRepoTestValues{
166+
Name: gitrepoName,
167+
Repo: inClusterRepoURL,
168+
Branch: gh.Branch,
169+
PollingInterval: "15s", // default
170+
TargetNamespace: targetNamespace, // to avoid conflicts with other tests
172171
})
173172
Expect(err).ToNot(HaveOccurred())
174173

@@ -270,18 +269,12 @@ var _ = Describe("Monitoring Git repos via HTTP for change", Label("infra-setup"
270269
clone, err = gh.Create(clonedir, testenv.AssetPath("gitrepo/sleeper-chart"), "examples")
271270
Expect(err).ToNot(HaveOccurred())
272271

273-
err = testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), struct {
274-
Name string
275-
Repo string
276-
Branch string
277-
PollingInterval string
278-
TargetNamespace string
279-
}{
280-
gitrepoName,
281-
inClusterRepoURL,
282-
gh.Branch,
283-
"24h", // prevent polling
284-
targetNamespace, // to avoid conflicts with other tests
272+
err = testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), gitRepoTestValues{
273+
Name: gitrepoName,
274+
Repo: inClusterRepoURL,
275+
Branch: gh.Branch,
276+
PollingInterval: "24h", // prevent polling
277+
TargetNamespace: targetNamespace, // to avoid conflicts with other tests
285278
})
286279
Expect(err).ToNot(HaveOccurred())
287280
})
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package singlecluster_test
2+
3+
// These test cases rely on a local git server, so that they can be run locally and against PRs.
4+
// For tests monitoring external git hosting providers, see `e2e/require-secrets`.
5+
6+
import (
7+
"encoding/base64"
8+
"fmt"
9+
"math/rand"
10+
"os"
11+
"path"
12+
"strings"
13+
14+
. "github.com/onsi/ginkgo/v2"
15+
. "github.com/onsi/gomega"
16+
17+
"github.com/rancher/fleet/e2e/testenv"
18+
"github.com/rancher/fleet/e2e/testenv/githelper"
19+
"github.com/rancher/fleet/e2e/testenv/kubectl"
20+
)
21+
22+
var _ = Describe("Testing go-getter CA bundles", Label("infra-setup"), func() {
23+
const (
24+
sleeper = "sleeper"
25+
entrypoint = "entrypoint"
26+
)
27+
28+
var (
29+
tmpDir string
30+
cloneDir string
31+
k kubectl.Command
32+
gh *githelper.Git
33+
gitrepoName string
34+
r = rand.New(rand.NewSource(GinkgoRandomSeed()))
35+
targetNamespace string
36+
// Build git repo URL reachable _within_ the cluster, for the GitRepo
37+
host = githelper.BuildGitHostname()
38+
)
39+
40+
getExternalRepoURL := func(repoName string) string {
41+
GinkgoHelper()
42+
addr, err := githelper.GetExternalRepoAddr(env, HTTPSPort, repoName)
43+
Expect(err).ToNot(HaveOccurred())
44+
addr = strings.Replace(addr, "http://", fmt.Sprintf("%s://", "https"), 1)
45+
return addr
46+
}
47+
48+
BeforeEach(func() {
49+
k = env.Kubectl.Namespace(env.Namespace)
50+
})
51+
52+
JustBeforeEach(func() {
53+
// Create the first repository
54+
addr := getExternalRepoURL("repo")
55+
gh = githelper.NewHTTP(addr)
56+
tmpDir, err := os.MkdirTemp("", "fleet-")
57+
Expect(err).ToNot(HaveOccurred())
58+
cloneDir = path.Join(tmpDir, "repo") // Fixed and built into the container image.
59+
gitrepoName = testenv.RandomFilename("gitjob-test", r)
60+
// Creates the content in the sleeperClusterName directory
61+
_, err = gh.Create(cloneDir, testenv.AssetPath("gitrepo/sleeper-chart"), sleeper)
62+
Expect(err).ToNot(HaveOccurred())
63+
64+
// Create the second repository
65+
Expect(err).ToNot(HaveOccurred())
66+
tmpAssetDir := path.Join(tmpDir, "entryPoint")
67+
err = os.Mkdir(tmpAssetDir, 0755)
68+
Expect(err).ToNot(HaveOccurred())
69+
url := "git::" + gh.GetInClusterURL(host, HTTPSPort, "repo?ref="+sleeper)
70+
err = os.WriteFile(
71+
path.Join(tmpAssetDir, "fleet.yaml"),
72+
fmt.Appendf([]byte{}, "helm:\n chart: %s\n", url),
73+
0755,
74+
)
75+
Expect(err).NotTo(HaveOccurred())
76+
77+
_, err = gh.Add(cloneDir, tmpAssetDir, entrypoint)
78+
Expect(err).ToNot(HaveOccurred())
79+
})
80+
81+
AfterEach(func() {
82+
_ = os.RemoveAll(tmpDir)
83+
_, _ = k.Delete("gitrepo", gitrepoName)
84+
85+
// Check that the bundle deployment resource has been deleted
86+
Eventually(func(g Gomega) {
87+
out, _ := k.Get(
88+
"bundledeployments",
89+
"-A",
90+
"-l",
91+
fmt.Sprintf("fleet.cattle.io/repo-name=%s", gitrepoName),
92+
)
93+
g.Expect(out).To(ContainSubstring("No resources found"))
94+
}).Should(Succeed())
95+
96+
_, _ = k.Delete("ns", targetNamespace)
97+
})
98+
99+
When("testing InsecureSkipTLSVerify", func() {
100+
BeforeEach(func() {
101+
targetNamespace = testenv.NewNamespaceName("target", r)
102+
})
103+
104+
It("should fail if InsecureSkipTLSVerify is false and an invalid certificate was provided", func() {
105+
// Create and apply GitRepo
106+
err := testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), gitRepoTestValues{
107+
Name: gitrepoName,
108+
Repo: gh.GetInClusterURL(host, HTTPSPort, "repo"),
109+
Branch: gh.Branch,
110+
PollingInterval: "15s", // default
111+
TargetNamespace: targetNamespace, // to avoid conflicts with other tests
112+
Path: entrypoint,
113+
InsecureSkipTLSVerify: false,
114+
CABundle: base64.StdEncoding.EncodeToString([]byte("invalid-ca-bundle")), // prevents Rancher CA bundles from being used
115+
})
116+
Expect(err).ToNot(HaveOccurred())
117+
118+
Eventually(func(g Gomega) {
119+
out, err := k.Get("gitrepo", gitrepoName, `-o=jsonpath={.status.conditions[?(@.type=="GitPolling")].message}`)
120+
g.Expect(err).ToNot(HaveOccurred())
121+
g.Expect(out).To(ContainSubstring("certificate signed by unknown authority"))
122+
}).Should(Succeed())
123+
})
124+
125+
It("should succeed if InsecureSkipTLSVerify is true and an invalid certificate was provided", func() {
126+
// Create and apply GitRepo
127+
err := testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), gitRepoTestValues{
128+
Name: gitrepoName,
129+
Repo: gh.GetInClusterURL(host, HTTPSPort, "repo"),
130+
Branch: gh.Branch,
131+
PollingInterval: "15s", // default
132+
TargetNamespace: targetNamespace, // to avoid conflicts with other tests
133+
Path: entrypoint,
134+
InsecureSkipTLSVerify: true,
135+
CABundle: base64.StdEncoding.EncodeToString([]byte("invalid-ca-bundle")), // prevents Rancher CA bundles from being used
136+
})
137+
Expect(err).ToNot(HaveOccurred())
138+
139+
Eventually(func(g Gomega) {
140+
out, err := k.Get("gitrepo", gitrepoName, `-o=jsonpath={.status.display.readyBundleDeployments}`)
141+
g.Expect(err).ToNot(HaveOccurred())
142+
g.Expect(out).To(ContainSubstring("1/1"))
143+
}).Should(Succeed())
144+
})
145+
})
146+
147+
When("testing custom CA bundles", func() {
148+
It("should succeed when using the Rancher CA bundles provided in ConfigMaps", func() {
149+
// Create and apply GitRepo
150+
err := testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), gitRepoTestValues{
151+
Name: gitrepoName,
152+
Repo: gh.GetInClusterURL(host, HTTPSPort, "repo"),
153+
Branch: gh.Branch,
154+
PollingInterval: "15s", // default
155+
TargetNamespace: targetNamespace, // to avoid conflicts with other tests
156+
Path: entrypoint,
157+
InsecureSkipTLSVerify: false,
158+
CABundle: "", // use Rancher CA bundles
159+
})
160+
Expect(err).ToNot(HaveOccurred())
161+
162+
Eventually(func(g Gomega) {
163+
out, err := k.Get("gitrepo", gitrepoName, `-o=jsonpath={.status.display.readyBundleDeployments}`)
164+
g.Expect(err).ToNot(HaveOccurred())
165+
g.Expect(out).To(ContainSubstring("1/1"))
166+
}).Should(Succeed())
167+
})
168+
169+
It("should succeed when using the correct CA bundle provided in GitRepo", func() {
170+
certsDir := os.Getenv("CI_OCI_CERTS_DIR")
171+
Expect(certsDir).ToNot(BeEmpty())
172+
helmCrtFile := path.Join(certsDir, "helm.crt")
173+
crt, err := os.ReadFile(helmCrtFile)
174+
Expect(err).ToNot(HaveOccurred(), "failed to open helm.crt file")
175+
encodedCert := base64.StdEncoding.EncodeToString(crt)
176+
// Create and apply GitRepo
177+
err = testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), gitRepoTestValues{
178+
Name: gitrepoName,
179+
Repo: gh.GetInClusterURL(host, HTTPSPort, "repo"),
180+
Branch: gh.Branch,
181+
PollingInterval: "15s", // default
182+
TargetNamespace: targetNamespace, // to avoid conflicts with other tests
183+
Path: entrypoint,
184+
InsecureSkipTLSVerify: false,
185+
CABundle: encodedCert,
186+
})
187+
Expect(err).ToNot(HaveOccurred())
188+
189+
Eventually(func(g Gomega) {
190+
out, err := k.Get("gitrepo", gitrepoName, `-o=jsonpath={.status.display.readyBundleDeployments}`)
191+
g.Expect(err).ToNot(HaveOccurred())
192+
g.Expect(out).To(ContainSubstring("1/1"))
193+
}).Should(Succeed())
194+
})
195+
})
196+
})

e2e/single-cluster/schedule_test.go

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
package singlecluster
1+
package singlecluster_test
22

33
import (
4-
"bytes"
5-
"encoding/json"
64
"fmt"
75
"math/rand"
86
"os"
@@ -113,18 +111,12 @@ var _ = Describe("Schedules", Label("infra-setup"), func() {
113111
}).Should(BeTrue())
114112

115113
// Apply a GitRepo
116-
err = testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), struct {
117-
Name string
118-
Repo string
119-
Branch string
120-
PollingInterval string
121-
TargetNamespace string
122-
}{
123-
gitrepoName,
124-
inClusterRepoURL,
125-
gh.Branch,
126-
"15s", // default
127-
targetNamespace, // to avoid conflicts with other tests
114+
err = testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), gitRepoTestValues{
115+
Name: gitrepoName,
116+
Repo: inClusterRepoURL,
117+
Branch: gh.Branch,
118+
PollingInterval: "15s", // default
119+
TargetNamespace: targetNamespace, // to avoid conflicts with other tests
128120
})
129121
Expect(err).ToNot(HaveOccurred())
130122

@@ -249,29 +241,6 @@ var _ = Describe("Schedules", Label("infra-setup"), func() {
249241
})
250242
})
251243

252-
// replace replaces string s with r in the file located at path. That file must exist and be writable.
253-
func replace(path string, s string, r string) {
254-
b, err := os.ReadFile(path)
255-
Expect(err).ToNot(HaveOccurred())
256-
257-
b = bytes.ReplaceAll(b, []byte(s), []byte(r))
258-
259-
err = os.WriteFile(path, b, 0644)
260-
Expect(err).ToNot(HaveOccurred())
261-
}
262-
263-
// getGitRepoStatus retrieves the status of the gitrepo with the provided name.
264-
func getGitRepoStatus(g Gomega, k kubectl.Command, name string) fleet.GitRepoStatus {
265-
gr, err := k.Get("gitrepo", name, "-o=json")
266-
267-
g.Expect(err).ToNot(HaveOccurred())
268-
269-
var gitrepo fleet.GitRepo
270-
_ = json.Unmarshal([]byte(gr), &gitrepo)
271-
272-
return gitrepo.Status
273-
}
274-
275244
func waitForBeginningOfNextMinute() {
276245
for {
277246
now := time.Now()

0 commit comments

Comments
 (0)