@@ -297,6 +297,8 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.O
297
297
// reconcileSource fetches the upstream OCI artifact metadata and content.
298
298
// If this fails, it records v1beta2.FetchFailedCondition=True on the object and returns early.
299
299
func (r * OCIRepositoryReconciler ) reconcileSource (ctx context.Context , obj * sourcev1.OCIRepository , metadata * sourcev1.Artifact , dir string ) (sreconcile.Result , error ) {
300
+ var auth authn.Authenticator
301
+
300
302
ctxTimeout , cancel := context .WithTimeout (ctx , obj .Spec .Timeout .Duration )
301
303
defer cancel ()
302
304
@@ -308,8 +310,6 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
308
310
conditions .Delete (obj , sourcev1 .SourceVerifiedCondition )
309
311
}
310
312
311
- options := r .craneOptions (ctxTimeout , obj .Spec .Insecure )
312
-
313
313
// Generate the registry credential keychain either from static credentials or using cloud OIDC
314
314
keychain , err := r .keychain (ctx , obj )
315
315
if err != nil {
@@ -320,10 +320,10 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
320
320
conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Err .Error ())
321
321
return sreconcile .ResultEmpty , e
322
322
}
323
- options = append (options , crane .WithAuthFromKeychain (keychain ))
324
323
325
324
if _ , ok := keychain .(soci.Anonymous ); obj .Spec .Provider != sourcev1 .GenericOCIProvider && ok {
326
- auth , authErr := oidcAuth (ctxTimeout , obj .Spec .URL , obj .Spec .Provider )
325
+ var authErr error
326
+ auth , authErr = oidcAuth (ctxTimeout , obj .Spec .URL , obj .Spec .Provider )
327
327
if authErr != nil && ! errors .Is (authErr , oci .ErrUnconfiguredProvider ) {
328
328
e := serror .NewGeneric (
329
329
fmt .Errorf ("failed to get credential from %s: %w" , obj .Spec .Provider , authErr ),
@@ -332,9 +332,6 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
332
332
conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Err .Error ())
333
333
return sreconcile .ResultEmpty , e
334
334
}
335
- if auth != nil {
336
- options = append (options , crane .WithAuth (auth ))
337
- }
338
335
}
339
336
340
337
// Generate the transport for remote operations
@@ -347,12 +344,11 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
347
344
conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Err .Error ())
348
345
return sreconcile .ResultEmpty , e
349
346
}
350
- if transport != nil {
351
- options = append (options , crane .WithTransport (transport ))
352
- }
347
+
348
+ opts := r .makeOptions (ctx , obj , withTransport (transport ), withKeychainOrAuth (keychain , auth ))
353
349
354
350
// Determine which artifact revision to pull
355
- url , err := r .getArtifactURL (obj , options )
351
+ url , err := r .getArtifactURL (obj , opts . craneOpts )
356
352
if err != nil {
357
353
if _ , ok := err .(invalidOCIURLError ); ok {
358
354
e := serror .NewStalling (
@@ -370,7 +366,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
370
366
}
371
367
372
368
// Get the upstream revision from the artifact digest
373
- revision , err := r .getRevision (url , options )
369
+ revision , err := r .getRevision (url , opts . craneOpts )
374
370
if err != nil {
375
371
e := serror .NewGeneric (
376
372
fmt .Errorf ("failed to determine artifact digest: %w" , err ),
@@ -401,7 +397,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
401
397
} else if ! obj .GetArtifact ().HasRevision (revision ) ||
402
398
conditions .GetObservedGeneration (obj , sourcev1 .SourceVerifiedCondition ) != obj .Generation ||
403
399
conditions .IsFalse (obj , sourcev1 .SourceVerifiedCondition ) {
404
- err := r .verifySignature (ctx , obj , url , keychain )
400
+ err := r .verifySignature (ctx , obj , url , opts . verifyOpts ... )
405
401
if err != nil {
406
402
provider := obj .Spec .Verify .Provider
407
403
if obj .Spec .Verify .SecretRef == nil {
@@ -425,7 +421,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
425
421
}
426
422
427
423
// Pull artifact from the remote container registry
428
- img , err := crane .Pull (url , options ... )
424
+ img , err := crane .Pull (url , opts . craneOpts ... )
429
425
if err != nil {
430
426
e := serror .NewGeneric (
431
427
fmt .Errorf ("failed to pull artifact from '%s': %w" , obj .Spec .URL , err ),
@@ -585,15 +581,15 @@ func (r *OCIRepositoryReconciler) digestFromRevision(revision string) string {
585
581
586
582
// verifySignature verifies the authenticity of the given image reference url. First, it tries using a key
587
583
// if a secret with a valid public key is provided. If not, it falls back to a keyless approach for verification.
588
- func (r * OCIRepositoryReconciler ) verifySignature (ctx context.Context , obj * sourcev1.OCIRepository , url string , keychain authn. Keychain ) error {
584
+ func (r * OCIRepositoryReconciler ) verifySignature (ctx context.Context , obj * sourcev1.OCIRepository , url string , opt ... remote. Option ) error {
589
585
ctxTimeout , cancel := context .WithTimeout (ctx , obj .Spec .Timeout .Duration )
590
586
defer cancel ()
591
587
592
588
provider := obj .Spec .Verify .Provider
593
589
switch provider {
594
590
case "cosign" :
595
591
defaultCosignOciOpts := []soci.Options {
596
- soci .WithAuthnKeychain ( keychain ),
592
+ soci .WithRemoteOptions ( opt ... ),
597
593
}
598
594
599
595
ref , err := name .ParseReference (url )
@@ -1125,3 +1121,46 @@ func (r *OCIRepositoryReconciler) notify(ctx context.Context, oldObj, newObj *so
1125
1121
}
1126
1122
}
1127
1123
}
1124
+
1125
+ func (r * OCIRepositoryReconciler ) makeOptions (ctxTimeout context.Context , obj * sourcev1.OCIRepository , opts ... Option ) remoteOptions {
1126
+ o := remoteOptions {
1127
+ craneOpts : r .craneOptions (ctxTimeout , obj .Spec .Insecure ),
1128
+ verifyOpts : []remote.Option {},
1129
+ }
1130
+
1131
+ for _ , opt := range opts {
1132
+ opt (& o )
1133
+ }
1134
+
1135
+ return o
1136
+ }
1137
+
1138
+ type remoteOptions struct {
1139
+ craneOpts []crane.Option
1140
+ verifyOpts []remote.Option
1141
+ }
1142
+
1143
+ type Option func (* remoteOptions )
1144
+
1145
+ func withKeychainOrAuth (keychain authn.Keychain , auth authn.Authenticator ) Option {
1146
+ return func (o * remoteOptions ) {
1147
+ if auth != nil {
1148
+ // auth take precedence over keychain here as we expect the caller to set
1149
+ // the auth only if it is required.
1150
+ o .verifyOpts = append (o .verifyOpts , remote .WithAuth (auth ))
1151
+ o .craneOpts = append (o .craneOpts , crane .WithAuth (auth ))
1152
+ } else {
1153
+ o .verifyOpts = append (o .verifyOpts , remote .WithAuthFromKeychain (keychain ))
1154
+ o .craneOpts = append (o .craneOpts , crane .WithAuthFromKeychain (keychain ))
1155
+ }
1156
+ }
1157
+ }
1158
+
1159
+ func withTransport (transport http.RoundTripper ) Option {
1160
+ return func (o * remoteOptions ) {
1161
+ if transport != nil {
1162
+ o .craneOpts = append (o .craneOpts , crane .WithTransport (transport ))
1163
+ o .verifyOpts = append (o .verifyOpts , remote .WithTransport (transport ))
1164
+ }
1165
+ }
1166
+ }
0 commit comments