Skip to content

Commit 172dec4

Browse files
committed
Test SSH as well as HTTP access to git
This commit rearranges update tests so that those that check that updates are made can be run against a git server using SSH as well as HTTP. The local clone, used to provoke automated updates and to check results, still uses HTTP. Those operations are not under test. libgit2 wants to be asked for authentication when using SSH, and will balk if it's not requested by the server. To avoid that, auth must be switched on for the git test server. This also switches auth on for HTTP, so it's necessary to use a git URL that includes credentials for setting things up with a local clone. I have also used that URL for the git-over-HTTP tests -- it's arguable whether it's necessary to test that works, here. Signed-off-by: Michael Bridgen <[email protected]>
1 parent 5d9f0f9 commit 172dec4

File tree

4 files changed

+119
-31
lines changed

4 files changed

+119
-31
lines changed

controllers/imageupdateautomation_controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ import (
5353
"github.com/fluxcd/pkg/runtime/metrics"
5454
"github.com/fluxcd/pkg/runtime/predicates"
5555
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
56-
gitstrat "github.com/fluxcd/source-controller/pkg/git"
57-
git "github.com/fluxcd/source-controller/pkg/git/common"
56+
git "github.com/fluxcd/source-controller/pkg/git"
57+
gitstrat "github.com/fluxcd/source-controller/pkg/git/strategy"
5858

5959
imagev1 "github.com/fluxcd/image-automation-controller/api/v1alpha1"
6060
"github.com/fluxcd/image-automation-controller/pkg/update"

controllers/update_test.go

Lines changed: 96 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ import (
2222
"fmt"
2323
"io/ioutil"
2424
"math/rand"
25+
"net/url"
2526
"os"
2627
"path/filepath"
28+
"strings"
2729
"time"
2830

2931
"github.com/go-git/go-billy/v5/memfs"
@@ -46,6 +48,7 @@ import (
4648
imagev1_reflect "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
4749
"github.com/fluxcd/pkg/apis/meta"
4850
"github.com/fluxcd/pkg/gittestserver"
51+
"github.com/fluxcd/pkg/ssh"
4952
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
5053

5154
imagev1 "github.com/fluxcd/image-automation-controller/api/v1alpha1"
@@ -69,12 +72,11 @@ func randStringRunes(n int) string {
6972

7073
var _ = Describe("ImageUpdateAutomation", func() {
7174
var (
72-
impl string
73-
branch string
74-
repositoryPath string
75-
repoURL string
76-
namespace *corev1.Namespace
77-
gitServer *gittestserver.GitServer
75+
branch string
76+
repositoryPath string
77+
namespace *corev1.Namespace
78+
username, password string
79+
gitServer *gittestserver.GitServer
7880
)
7981

8082
// Start the git server
@@ -89,10 +91,15 @@ var _ = Describe("ImageUpdateAutomation", func() {
8991
var err error
9092
gitServer, err = gittestserver.NewTempGitServer()
9193
Expect(err).NotTo(HaveOccurred())
94+
username = randStringRunes(5)
95+
password = randStringRunes(5)
96+
// using authentication makes using the server more fiddly in
97+
// general, but is required for testing SSH.
98+
gitServer.Auth(username, password)
9299
gitServer.AutoCreate()
93100
Expect(gitServer.StartHTTP()).To(Succeed())
94-
95-
repoURL = gitServer.HTTPAddress() + repositoryPath
101+
gitServer.KeyDir(filepath.Join(gitServer.Root(), "keys"))
102+
Expect(gitServer.ListenSSH()).To(Succeed())
96103
})
97104

98105
AfterEach(func() {
@@ -104,8 +111,20 @@ var _ = Describe("ImageUpdateAutomation", func() {
104111
Expect(initGitRepo(gitServer, "testdata/appconfig", branch, repositoryPath)).To(Succeed())
105112
})
106113

114+
// These are used for end-to-end tests; withImagePolicy is
115+
// effectively parameterised on these two values.
116+
var (
117+
// set the proto and impl in BeforeEach
118+
proto string
119+
impl string
120+
)
121+
107122
withImagePolicy := func() {
108123
var (
124+
// for cloning locally
125+
cloneLocalRepoURL string
126+
// for the controller
127+
repoURL string
109128
localRepo *git.Repository
110129
policy *imagev1_reflect.ImagePolicy
111130
policyKey types.NamespacedName
@@ -117,13 +136,31 @@ var _ = Describe("ImageUpdateAutomation", func() {
117136
const evenLatestImage = "helloworld:1.2.0"
118137

119138
BeforeEach(func() {
139+
cloneLocalRepoURL = gitServer.HTTPAddressWithCredentials() + repositoryPath
140+
if proto == "http" {
141+
repoURL = cloneLocalRepoURL // NB not testing auth for git over HTTP
142+
} else if proto == "ssh" {
143+
sshURL := gitServer.SSHAddress()
144+
// this is expected to use 127.0.0.1, but host key
145+
// checking usually wants a hostname, so use
146+
// "localhost".
147+
sshURL = strings.Replace(sshURL, "127.0.0.1", "localhost", 1)
148+
repoURL = sshURL + repositoryPath
149+
go func() {
150+
defer GinkgoRecover()
151+
gitServer.StartSSH()
152+
}()
153+
} else {
154+
Fail("proto not set to http or ssh")
155+
}
156+
120157
commitMessage = "Commit a difference " + randStringRunes(5)
121158

122159
Expect(initGitRepo(gitServer, "testdata/appconfig", branch, repositoryPath)).To(Succeed())
123160

124161
var err error
125162
localRepo, err = git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
126-
URL: repoURL,
163+
URL: cloneLocalRepoURL,
127164
RemoteName: "origin",
128165
ReferenceName: plumbing.NewBranchReferenceName(branch),
129166
})
@@ -145,6 +182,31 @@ var _ = Describe("ImageUpdateAutomation", func() {
145182
GitImplementation: impl,
146183
},
147184
}
185+
186+
// If using SSH, we need to provide an identity (private
187+
// key) and known_hosts file in a secret.
188+
if proto == "ssh" {
189+
url, err := url.Parse(repoURL)
190+
Expect(err).ToNot(HaveOccurred())
191+
knownhosts, err := ssh.ScanHostKey(url.Host, 5*time.Second)
192+
Expect(err).ToNot(HaveOccurred())
193+
keygen := ssh.NewRSAGenerator(2048)
194+
pair, err := keygen.Generate()
195+
Expect(err).ToNot(HaveOccurred())
196+
197+
sec := &corev1.Secret{
198+
StringData: map[string]string{
199+
"known_hosts": string(knownhosts),
200+
"identity": string(pair.PrivateKey),
201+
"identity.pub": string(pair.PublicKey),
202+
},
203+
}
204+
sec.Name = "git-secret-" + randStringRunes(5)
205+
sec.Namespace = namespace.Name
206+
Expect(k8sClient.Create(context.Background(), sec)).To(Succeed())
207+
gitRepo.Spec.SecretRef = &meta.LocalObjectReference{Name: sec.Name}
208+
}
209+
148210
Expect(k8sClient.Create(context.Background(), gitRepo)).To(Succeed())
149211

150212
policyKey = types.NamespacedName{
@@ -180,6 +242,7 @@ var _ = Describe("ImageUpdateAutomation", func() {
180242
AfterEach(func() {
181243
Expect(k8sClient.Delete(context.Background(), namespace)).To(Succeed())
182244
Expect(k8sClient.Delete(context.Background(), policy)).To(Succeed())
245+
Expect(gitServer.StopSSH()).To(Succeed())
183246
})
184247

185248
Context("defaulting", func() {
@@ -234,7 +297,7 @@ var _ = Describe("ImageUpdateAutomation", func() {
234297
BeforeEach(func() {
235298
// Insert a setter reference into the deployment file,
236299
// before creating the automation object itself.
237-
commitInRepo(repoURL, branch, "Install setter marker", func(tmp string) {
300+
commitInRepo(cloneLocalRepoURL, branch, "Install setter marker", func(tmp string) {
238301
replaceMarker(tmp, policyKey)
239302
})
240303

@@ -291,7 +354,7 @@ var _ = Describe("ImageUpdateAutomation", func() {
291354
Expect(newObj.Status.LastPushCommit).To(Equal(head.Hash().String()))
292355
Expect(newObj.Status.LastPushTime).ToNot(BeNil())
293356

294-
compareRepoWithExpected(repoURL, branch, "testdata/appconfig-setters-expected", func(tmp string) {
357+
compareRepoWithExpected(cloneLocalRepoURL, branch, "testdata/appconfig-setters-expected", func(tmp string) {
295358
replaceMarker(tmp, policyKey)
296359
})
297360
})
@@ -338,21 +401,35 @@ var _ = Describe("ImageUpdateAutomation", func() {
338401
}
339402

340403
Context("Using go-git", func() {
341-
BeforeEach(func() {
342-
impl = sourcev1.GoGitImplementation
404+
BeforeEach(func() { impl = sourcev1.GoGitImplementation })
405+
406+
Context("with HTTP", func() {
407+
BeforeEach(func() { proto = "http" })
408+
Describe("with image policy", withImagePolicy)
343409
})
344410

345-
Context("with image policy", withImagePolicy)
411+
Context("with SSH", func() {
412+
BeforeEach(func() { proto = "ssh" })
413+
Describe("with image policy", withImagePolicy)
414+
})
346415
})
347416

348417
Context("Using libgit2", func() {
349-
BeforeEach(func() {
350-
impl = sourcev1.LibGit2Implementation
418+
BeforeEach(func() { impl = sourcev1.LibGit2Implementation })
419+
420+
Context("with HTTP", func() {
421+
BeforeEach(func() { proto = "http" })
422+
Describe("with image policy", withImagePolicy)
351423
})
352424

353-
Context("with image policy", withImagePolicy)
425+
// Marked "Pending" because the libgit2 SSH implementation
426+
// won't work with the gittestserver yet -- see
427+
// https://github.com/fluxcd/source-controller/issues/287
428+
Context("with SSH", func() {
429+
BeforeEach(func() { proto = "ssh" })
430+
Describe("with image policy", withImagePolicy)
431+
})
354432
})
355-
356433
})
357434

358435
func expectCommittedAndPushed(conditions []metav1.Condition) {
@@ -498,7 +575,7 @@ func initGitRepo(gitServer *gittestserver.GitServer, fixture, branch, repository
498575

499576
remote, err := repo.CreateRemote(&config.RemoteConfig{
500577
Name: "origin",
501-
URLs: []string{gitServer.HTTPAddress() + repositoryPath},
578+
URLs: []string{gitServer.HTTPAddressWithCredentials() + repositoryPath},
502579
})
503580
if err != nil {
504581
return err

go.mod

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,18 @@ require (
1111
github.com/fluxcd/image-automation-controller/api v0.4.0
1212
github.com/fluxcd/image-reflector-controller/api v0.4.0
1313
github.com/fluxcd/pkg/apis/meta v0.7.0
14-
github.com/fluxcd/pkg/gittestserver v0.1.0
14+
github.com/fluxcd/pkg/gittestserver v0.2.1
1515
github.com/fluxcd/pkg/runtime v0.8.1
16-
github.com/fluxcd/source-controller v0.7.0
16+
github.com/fluxcd/pkg/ssh v0.0.5
17+
github.com/fluxcd/source-controller v0.7.4
1718
// If you bump this, change SOURCE_VER in the Makefile to match
18-
github.com/fluxcd/source-controller/api v0.7.0
19+
github.com/fluxcd/source-controller/api v0.7.4
1920
github.com/go-git/go-billy/v5 v5.0.0
2021
github.com/go-git/go-git/v5 v5.2.0
2122
github.com/go-logr/logr v0.3.0
2223
github.com/go-openapi/spec v0.19.5
2324
github.com/google/go-containerregistry v0.1.1
24-
github.com/libgit2/git2go/v31 v31.3.0
25+
github.com/libgit2/git2go/v31 v31.4.7
2526
github.com/onsi/ginkgo v1.14.1
2627
github.com/onsi/gomega v1.10.2
2728
github.com/otiai10/copy v1.2.0

go.sum

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,11 @@ github.com/fluxcd/image-reflector-controller/api v0.4.0 h1:/7mxmTsjmwmzTchWG06Fa
306306
github.com/fluxcd/image-reflector-controller/api v0.4.0/go.mod h1:MS3mGjZLnzZsfSqVLGbp0WNJr/k8XRFpw4G6ApLFTbc=
307307
github.com/fluxcd/pkg/apis/meta v0.7.0 h1:5e8gm4OLqjuKWdrOIY5DEEsjcwzyJFK8rCDesJ+V8IY=
308308
github.com/fluxcd/pkg/apis/meta v0.7.0/go.mod h1:yHuY8kyGHYz22I0jQzqMMGCcHViuzC/WPdo9Gisk8Po=
309-
github.com/fluxcd/pkg/gittestserver v0.1.0 h1:BvIG+bBhgbmqhtpSS2qUpOXRIL1P1Ow2jauloH8X86U=
310309
github.com/fluxcd/pkg/gittestserver v0.1.0/go.mod h1:HWZaoib03fQeSsauCAN2iAFdr6bnjKQ+CFxMFD2mwDY=
310+
github.com/fluxcd/pkg/gittestserver v0.2.1 h1:SidG8/2hPVEV4XL7ofI76RMfen9zt1LLIoXddzkAhhI=
311+
github.com/fluxcd/pkg/gittestserver v0.2.1/go.mod h1:HWZaoib03fQeSsauCAN2iAFdr6bnjKQ+CFxMFD2mwDY=
311312
github.com/fluxcd/pkg/helmtestserver v0.1.0/go.mod h1:3L+tbPn74PsHwHsyhbfk/kZAosrwMFTTA92XEFiwVAE=
312313
github.com/fluxcd/pkg/lockedfile v0.0.5/go.mod h1:uAtPUBId6a2RqO84MTH5HKGX0SbM1kNW3Wr/FhYyDVA=
313-
github.com/fluxcd/pkg/runtime v0.8.0/go.mod h1:tQwEN+RESjJmtwSSv7I+6bkNM9raIXpGsCjruaIVX6A=
314314
github.com/fluxcd/pkg/runtime v0.8.1 h1:8UxNz7GeI/HC3U5tpNCfrjRx2V7UjUegQOwCsd+EWxk=
315315
github.com/fluxcd/pkg/runtime v0.8.1/go.mod h1:tQwEN+RESjJmtwSSv7I+6bkNM9raIXpGsCjruaIVX6A=
316316
github.com/fluxcd/pkg/ssh v0.0.5 h1:rnbFZ7voy2JBlUfMbfyqArX2FYaLNpDhccGFC3qW83A=
@@ -319,10 +319,10 @@ github.com/fluxcd/pkg/testserver v0.0.2/go.mod h1:pgUZTh9aQ44FSTQo+5NFlh7YMbUfdz
319319
github.com/fluxcd/pkg/untar v0.0.5/go.mod h1:O6V9+rtl8c1mHBafgqFlJN6zkF1HS5SSYn7RpQJ/nfw=
320320
github.com/fluxcd/pkg/version v0.0.1 h1:/8asQoDXSThz3csiwi4Qo8Zb6blAxLXbtxNgeMJ9bCg=
321321
github.com/fluxcd/pkg/version v0.0.1/go.mod h1:WAF4FEEA9xyhngF8TDxg3UPu5fA1qhEYV8Pmi2Il01Q=
322-
github.com/fluxcd/source-controller v0.7.0 h1:OvvD0a9ZhlIshZt0NzkXJ5hAD8Zce7xERFC1UyhfXZA=
323-
github.com/fluxcd/source-controller v0.7.0/go.mod h1:hfpk9y5iDJlSZqL+/OZTqvYDFZgIKz1PV26bOy404+M=
324-
github.com/fluxcd/source-controller/api v0.7.0 h1:QDpr6ZjHtTxw+mc+mZ1p9qRujHb+PzPdoQP3YgWlqOA=
325-
github.com/fluxcd/source-controller/api v0.7.0/go.mod h1:u2sdc/QDm0tzXHL7mZVj928hc3MMU+4mKCuAQg+94Bk=
322+
github.com/fluxcd/source-controller v0.7.4 h1:1I+vPPJUHI4f1775E34EUBbATLt2QfEykvlfFJRMiUk=
323+
github.com/fluxcd/source-controller v0.7.4/go.mod h1:W/C32SFn9P7WXwjILjhAfN7F+zuWG5YAaQUUgHDlbes=
324+
github.com/fluxcd/source-controller/api v0.7.4 h1:Hy29SUyanKNHbb4AQZo7PqzmTx4y8TfkeO0GqBcb5PE=
325+
github.com/fluxcd/source-controller/api v0.7.4/go.mod h1:u2sdc/QDm0tzXHL7mZVj928hc3MMU+4mKCuAQg+94Bk=
326326
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
327327
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
328328
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
@@ -548,6 +548,8 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
548548
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
549549
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
550550
github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg=
551+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
552+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
551553
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
552554
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
553555
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -694,6 +696,8 @@ github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
694696
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
695697
github.com/libgit2/git2go/v31 v31.3.0 h1:d8ciyYVKir+gKwra3KuNxTyVvbgGKn4admdt1PNNAOg=
696698
github.com/libgit2/git2go/v31 v31.3.0/go.mod h1:mnc0hPGPs0nDi9INrurTpioeRzje9DvSXqON/+JEhwY=
699+
github.com/libgit2/git2go/v31 v31.4.7 h1:P85qB5at5un4qPqUcvOZbAom7P0G4KAG/OLVyD29kQ0=
700+
github.com/libgit2/git2go/v31 v31.4.7/go.mod h1:c/rkJcBcUFx6wHaT++UwNpKvIsmPNqCeQ/vzO4DrEec=
697701
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
698702
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
699703
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
@@ -1120,6 +1124,8 @@ golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPh
11201124
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
11211125
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
11221126
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
1127+
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
1128+
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
11231129
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
11241130
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
11251131
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1277,6 +1283,10 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
12771283
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
12781284
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY=
12791285
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1286+
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso=
1287+
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1288+
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
1289+
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
12801290
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
12811291
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
12821292
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

0 commit comments

Comments
 (0)