@@ -22,9 +22,7 @@ import (
22
22
"io/ioutil"
23
23
"os"
24
24
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"
28
26
"github.com/go-git/go-git/v5/plumbing/transport"
29
27
"github.com/go-logr/logr"
30
28
corev1 "k8s.io/api/core/v1"
@@ -121,34 +119,18 @@ func (r *GitRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, o
121
119
}
122
120
123
121
func (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
147
127
}
128
+ defer os .RemoveAll (tmpGit )
148
129
149
130
// determine auth method
150
131
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 {
152
134
name := types.NamespacedName {
153
135
Namespace : repository .GetNamespace (),
154
136
Name : repository .Spec .SecretRef .Name ,
@@ -161,173 +143,32 @@ func (r *GitRepositoryReconciler) sync(ctx context.Context, repository sourcev1.
161
143
return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .AuthenticationFailedReason , err .Error ()), err
162
144
}
163
145
164
- method , cleanup , err := intgit . AuthMethodFromSecret ( repository . Spec . URL , secret )
146
+ auth , err = authStrategy . Method ( secret )
165
147
if err != nil {
166
148
err = fmt .Errorf ("auth error: %w" , err )
167
149
return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .AuthenticationFailedReason , err .Error ()), err
168
150
}
169
- if cleanup != nil {
170
- defer cleanup ()
171
- }
172
- auth = method
173
151
}
174
152
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 )
177
155
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 )
280
156
return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .GitOperationFailedReason , err .Error ()), err
281
157
}
282
158
283
159
// verify PGP signature
284
160
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 ,
298
163
Name : repository .Spec .Verification .SecretRef .Name ,
299
- }
300
-
301
- var secret corev1.Secret
302
- err = r .Client .Get (ctx , name , & secret )
164
+ }, commit )
303
165
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 )
318
166
return sourcev1 .GitRepositoryNotReady (repository , sourcev1 .VerificationFailedReason , err .Error ()), err
319
167
}
320
168
}
321
169
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
-
329
170
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 )
331
172
332
173
// create artifact dir
333
174
err = r .Storage .MkdirAll (artifact )
@@ -388,6 +229,29 @@ func (r *GitRepositoryReconciler) shouldResetStatus(repository sourcev1.GitRepos
388
229
}
389
230
}
390
231
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
+
391
255
// gc performs a garbage collection on all but current artifacts of
392
256
// the given repository.
393
257
func (r * GitRepositoryReconciler ) gc (repository sourcev1.GitRepository ) error {
0 commit comments