@@ -22,9 +22,7 @@ import (
2222 "io/ioutil"
2323 "os"
2424
25- "github.com/blang/semver"
26- "github.com/go-git/go-git/v5"
27- "github.com/go-git/go-git/v5/plumbing"
25+ "github.com/go-git/go-git/v5/plumbing/object"
2826 "github.com/go-git/go-git/v5/plumbing/transport"
2927 "github.com/go-logr/logr"
3028 corev1 "k8s.io/api/core/v1"
@@ -121,34 +119,18 @@ func (r *GitRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, o
121119}
122120
123121func (r * GitRepositoryReconciler ) sync (ctx context.Context , repository sourcev1.GitRepository ) (sourcev1.GitRepository , error ) {
124- // set defaults: master branch, no tags fetching, max two commits
125- branch := "master"
126- revision := ""
127- tagMode := git .NoTags
128- depth := 2
129-
130- // determine ref
131- refName := plumbing .NewBranchReferenceName (branch )
132- if repository .Spec .Reference != nil {
133- if repository .Spec .Reference .Branch != "" {
134- branch = repository .Spec .Reference .Branch
135- refName = plumbing .NewBranchReferenceName (branch )
136- }
137- if repository .Spec .Reference .Commit != "" {
138- depth = 0
139- } else {
140- if repository .Spec .Reference .Tag != "" {
141- refName = plumbing .NewTagReferenceName (repository .Spec .Reference .Tag )
142- }
143- if repository .Spec .Reference .SemVer != "" {
144- tagMode = git .AllTags
145- }
146- }
122+ // create tmp dir for the Git clone
123+ tmpGit , err := ioutil .TempDir ("" , repository .Name )
124+ if err != nil {
125+ err = fmt .Errorf ("tmp dir error: %w" , err )
126+ return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .StorageOperationFailedReason , err .Error ()), err
147127 }
128+ defer os .RemoveAll (tmpGit )
148129
149130 // determine auth method
150131 var auth transport.AuthMethod
151- if repository .Spec .SecretRef != nil {
132+ authStrategy := intgit .AuthSecretStrategyForURL (repository .Spec .URL )
133+ if repository .Spec .SecretRef != nil && authStrategy != nil {
152134 name := types.NamespacedName {
153135 Namespace : repository .GetNamespace (),
154136 Name : repository .Spec .SecretRef .Name ,
@@ -161,173 +143,32 @@ func (r *GitRepositoryReconciler) sync(ctx context.Context, repository sourcev1.
161143 return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .AuthenticationFailedReason , err .Error ()), err
162144 }
163145
164- method , cleanup , err := intgit . AuthMethodFromSecret ( repository . Spec . URL , secret )
146+ auth , err = authStrategy . Method ( secret )
165147 if err != nil {
166148 err = fmt .Errorf ("auth error: %w" , err )
167149 return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .AuthenticationFailedReason , err .Error ()), err
168150 }
169- if cleanup != nil {
170- defer cleanup ()
171- }
172- auth = method
173151 }
174152
175- // create tmp dir for the Git clone
176- tmpGit , err := ioutil . TempDir ( "" , repository .Name )
153+ checkoutStrategy := intgit . CheckoutStrategyForRef ( repository . Spec . Reference )
154+ commit , revision , err := checkoutStrategy . Checkout ( ctx , tmpGit , repository .Spec . URL , auth )
177155 if err != nil {
178- err = fmt .Errorf ("tmp dir error: %w" , err )
179- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .StorageOperationFailedReason , err .Error ()), err
180- }
181- defer os .RemoveAll (tmpGit )
182-
183- // clone to tmp
184- gitCtx , cancel := context .WithTimeout (ctx , repository .GetTimeout ())
185- repo , err := git .PlainCloneContext (gitCtx , tmpGit , false , & git.CloneOptions {
186- URL : repository .Spec .URL ,
187- Auth : auth ,
188- RemoteName : "origin" ,
189- ReferenceName : refName ,
190- SingleBranch : true ,
191- NoCheckout : false ,
192- Depth : depth ,
193- RecurseSubmodules : 0 ,
194- Progress : nil ,
195- Tags : tagMode ,
196- })
197- cancel ()
198- if err != nil {
199- err = fmt .Errorf ("git clone error: %w" , err )
200- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
201- }
202-
203- // checkout commit or tag
204- if repository .Spec .Reference != nil {
205- if commit := repository .Spec .Reference .Commit ; commit != "" {
206- w , err := repo .Worktree ()
207- if err != nil {
208- err = fmt .Errorf ("git worktree error: %w" , err )
209- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
210- }
211-
212- err = w .Checkout (& git.CheckoutOptions {
213- Hash : plumbing .NewHash (commit ),
214- Force : true ,
215- })
216- if err != nil {
217- err = fmt .Errorf ("git checkout '%s' for '%s' error: %w" , commit , branch , err )
218- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
219- }
220- } else if exp := repository .Spec .Reference .SemVer ; exp != "" {
221- rng , err := semver .ParseRange (exp )
222- if err != nil {
223- err = fmt .Errorf ("semver parse range error: %w" , err )
224- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
225- }
226-
227- repoTags , err := repo .Tags ()
228- if err != nil {
229- err = fmt .Errorf ("git list tags error: %w" , err )
230- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
231- }
232-
233- tags := make (map [string ]string )
234- _ = repoTags .ForEach (func (t * plumbing.Reference ) error {
235- tags [t .Name ().Short ()] = t .Strings ()[1 ]
236- return nil
237- })
238-
239- svTags := make (map [string ]string )
240- var svers []semver.Version
241- for tag , _ := range tags {
242- v , _ := semver .ParseTolerant (tag )
243- if rng (v ) {
244- svers = append (svers , v )
245- svTags [v .String ()] = tag
246- }
247- }
248-
249- if len (svers ) > 0 {
250- semver .Sort (svers )
251- v := svers [len (svers )- 1 ]
252- t := svTags [v .String ()]
253- commit := tags [t ]
254- revision = fmt .Sprintf ("%s/%s" , t , commit )
255-
256- w , err := repo .Worktree ()
257- if err != nil {
258- err = fmt .Errorf ("git worktree error: %w" , err )
259- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
260- }
261-
262- err = w .Checkout (& git.CheckoutOptions {
263- Hash : plumbing .NewHash (commit ),
264- })
265- if err != nil {
266- err = fmt .Errorf ("git checkout error: %w" , err )
267- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
268- }
269- } else {
270- err = fmt .Errorf ("no match found for semver: %s" , repository .Spec .Reference .SemVer )
271- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
272- }
273- }
274- }
275-
276- // read commit hash
277- ref , err := repo .Head ()
278- if err != nil {
279- err = fmt .Errorf ("git resolve HEAD error: %w" , err )
280156 return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
281157 }
282158
283159 // verify PGP signature
284160 if repository .Spec .Verification != nil {
285- commit , err := repo .CommitObject (ref .Hash ())
286- if err != nil {
287- err = fmt .Errorf ("git resolve HEAD error: %w" , err )
288- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
289- }
290-
291- if commit .PGPSignature == "" {
292- err = fmt .Errorf ("PGP signature not found for commit '%s'" , ref .Hash ())
293- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .VerificationFailedReason , err .Error ()), err
294- }
295-
296- name := types.NamespacedName {
297- Namespace : repository .GetNamespace (),
161+ err := r .verify (ctx , types.NamespacedName {
162+ Namespace : repository .Namespace ,
298163 Name : repository .Spec .Verification .SecretRef .Name ,
299- }
300-
301- var secret corev1.Secret
302- err = r .Client .Get (ctx , name , & secret )
164+ }, commit )
303165 if err != nil {
304- err = fmt .Errorf ("PGP public keys secret error: %w" , err )
305- return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .VerificationFailedReason , err .Error ()), err
306- }
307-
308- var verified bool
309- for _ , bytes := range secret .Data {
310- if _ , err := commit .Verify (string (bytes )); err == nil {
311- verified = true
312- break
313- }
314- }
315-
316- if ! verified {
317- err = fmt .Errorf ("PGP signature of '%s' can't be verified" , commit .Author )
318166 return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .VerificationFailedReason , err .Error ()), err
319167 }
320168 }
321169
322- if revision == "" {
323- revision = fmt .Sprintf ("%s/%s" , branch , ref .Hash ().String ())
324- if repository .Spec .Reference != nil && repository .Spec .Reference .Tag != "" {
325- revision = fmt .Sprintf ("%s/%s" , repository .Spec .Reference .Tag , ref .Hash ().String ())
326- }
327- }
328-
329170 artifact := r .Storage .ArtifactFor (repository .Kind , repository .ObjectMeta .GetObjectMeta (),
330- fmt .Sprintf ("%s.tar.gz" , ref .Hash () .String ()), revision )
171+ fmt .Sprintf ("%s.tar.gz" , commit .Hash .String ()), revision )
331172
332173 // create artifact dir
333174 err = r .Storage .MkdirAll (artifact )
@@ -388,6 +229,29 @@ func (r *GitRepositoryReconciler) shouldResetStatus(repository sourcev1.GitRepos
388229 }
389230}
390231
232+ func (r * GitRepositoryReconciler ) verify (ctx context.Context , publicKeySecret types.NamespacedName , commit * object.Commit ) error {
233+ if commit .PGPSignature == "" {
234+ return fmt .Errorf ("no PGP signature found for commit: %s" , commit .Hash )
235+ }
236+
237+ var secret corev1.Secret
238+ if err := r .Client .Get (ctx , publicKeySecret , & secret ); err != nil {
239+ return fmt .Errorf ("PGP public keys secret error: %w" , err )
240+ }
241+
242+ var verified bool
243+ for _ , bytes := range secret .Data {
244+ if _ , err := commit .Verify (string (bytes )); err == nil {
245+ verified = true
246+ break
247+ }
248+ }
249+ if ! verified {
250+ return fmt .Errorf ("PGP signature '%s' of '%s' can't be verified" , commit .PGPSignature , commit .Author )
251+ }
252+ return nil
253+ }
254+
391255// gc performs a garbage collection on all but current artifacts of
392256// the given repository.
393257func (r * GitRepositoryReconciler ) gc (repository sourcev1.GitRepository ) error {
0 commit comments