@@ -299,6 +299,8 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, obj *sourcev1.O
299299// reconcileSource fetches the upstream OCI artifact metadata and content.
300300// If this fails, it records v1beta2.FetchFailedCondition=True on the object and returns early.
301301func (r * OCIRepositoryReconciler ) reconcileSource (ctx context.Context , obj * sourcev1.OCIRepository , metadata * sourcev1.Artifact , dir string ) (sreconcile.Result , error ) {
302+ var auth authn.Authenticator
303+
302304 ctxTimeout , cancel := context .WithTimeout (ctx , obj .Spec .Timeout .Duration )
303305 defer cancel ()
304306
@@ -310,8 +312,6 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
310312 conditions .Delete (obj , sourcev1 .SourceVerifiedCondition )
311313 }
312314
313- options := r .craneOptions (ctxTimeout , obj .Spec .Insecure )
314-
315315 // Generate the registry credential keychain either from static credentials or using cloud OIDC
316316 keychain , err := r .keychain (ctx , obj )
317317 if err != nil {
@@ -322,10 +322,10 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
322322 conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Err .Error ())
323323 return sreconcile .ResultEmpty , e
324324 }
325- options = append (options , crane .WithAuthFromKeychain (keychain ))
326325
327326 if _ , ok := keychain .(soci.Anonymous ); obj .Spec .Provider != sourcev1 .GenericOCIProvider && ok {
328- auth , authErr := oidcAuth (ctxTimeout , obj .Spec .URL , obj .Spec .Provider )
327+ var authErr error
328+ auth , authErr = oidcAuth (ctxTimeout , obj .Spec .URL , obj .Spec .Provider )
329329 if authErr != nil && ! errors .Is (authErr , oci .ErrUnconfiguredProvider ) {
330330 e := serror .NewGeneric (
331331 fmt .Errorf ("failed to get credential from %s: %w" , obj .Spec .Provider , authErr ),
@@ -334,9 +334,6 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
334334 conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Err .Error ())
335335 return sreconcile .ResultEmpty , e
336336 }
337- if auth != nil {
338- options = append (options , crane .WithAuth (auth ))
339- }
340337 }
341338
342339 // Generate the transport for remote operations
@@ -349,12 +346,11 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
349346 conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , e .Err .Error ())
350347 return sreconcile .ResultEmpty , e
351348 }
352- if transport != nil {
353- options = append (options , crane .WithTransport (transport ))
354- }
349+
350+ opts := makeRemoteOptions (ctx , obj , transport , keychain , auth )
355351
356352 // Determine which artifact revision to pull
357- url , err := r .getArtifactURL (obj , options )
353+ url , err := r .getArtifactURL (obj , opts . craneOpts )
358354 if err != nil {
359355 if _ , ok := err .(invalidOCIURLError ); ok {
360356 e := serror .NewStalling (
@@ -372,7 +368,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
372368 }
373369
374370 // Get the upstream revision from the artifact digest
375- revision , err := r .getRevision (url , options )
371+ revision , err := r .getRevision (url , opts . craneOpts )
376372 if err != nil {
377373 e := serror .NewGeneric (
378374 fmt .Errorf ("failed to determine artifact digest: %w" , err ),
@@ -403,7 +399,18 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
403399 } else if ! obj .GetArtifact ().HasRevision (revision ) ||
404400 conditions .GetObservedGeneration (obj , sourcev1 .SourceVerifiedCondition ) != obj .Generation ||
405401 conditions .IsFalse (obj , sourcev1 .SourceVerifiedCondition ) {
406- err := r .verifySignature (ctx , obj , url , keychain )
402+
403+ // Insecure is not supported for verification
404+ if obj .Spec .Insecure {
405+ e := serror .NewGeneric (
406+ fmt .Errorf ("cosign does not support insecure registries" ),
407+ sourcev1 .VerificationError ,
408+ )
409+ conditions .MarkFalse (obj , sourcev1 .SourceVerifiedCondition , e .Reason , e .Err .Error ())
410+ return sreconcile .ResultEmpty , e
411+ }
412+
413+ err := r .verifySignature (ctx , obj , url , opts .verifyOpts ... )
407414 if err != nil {
408415 provider := obj .Spec .Verify .Provider
409416 if obj .Spec .Verify .SecretRef == nil {
@@ -429,7 +436,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
429436 }
430437
431438 // Pull artifact from the remote container registry
432- img , err := crane .Pull (url , options ... )
439+ img , err := crane .Pull (url , opts . craneOpts ... )
433440 if err != nil {
434441 e := serror .NewGeneric (
435442 fmt .Errorf ("failed to pull artifact from '%s': %w" , obj .Spec .URL , err ),
@@ -589,15 +596,15 @@ func (r *OCIRepositoryReconciler) digestFromRevision(revision string) string {
589596
590597// verifySignature verifies the authenticity of the given image reference url. First, it tries using a key
591598// if a secret with a valid public key is provided. If not, it falls back to a keyless approach for verification.
592- func (r * OCIRepositoryReconciler ) verifySignature (ctx context.Context , obj * sourcev1.OCIRepository , url string , keychain authn. Keychain ) error {
599+ func (r * OCIRepositoryReconciler ) verifySignature (ctx context.Context , obj * sourcev1.OCIRepository , url string , opt ... remote. Option ) error {
593600 ctxTimeout , cancel := context .WithTimeout (ctx , obj .Spec .Timeout .Duration )
594601 defer cancel ()
595602
596603 provider := obj .Spec .Verify .Provider
597604 switch provider {
598605 case "cosign" :
599606 defaultCosignOciOpts := []soci.Options {
600- soci .WithAuthnKeychain ( keychain ),
607+ soci .WithRemoteOptions ( opt ... ),
601608 }
602609
603610 ref , err := name .ParseReference (url )
@@ -857,21 +864,6 @@ func oidcAuth(ctx context.Context, url, provider string) (authn.Authenticator, e
857864 return login .NewManager ().Login (ctx , u , ref , opts )
858865}
859866
860- // craneOptions sets the auth headers, timeout and user agent
861- // for all operations against remote container registries.
862- func (r * OCIRepositoryReconciler ) craneOptions (ctx context.Context , insecure bool ) []crane.Option {
863- options := []crane.Option {
864- crane .WithContext (ctx ),
865- crane .WithUserAgent (oci .UserAgent ),
866- }
867-
868- if insecure {
869- options = append (options , crane .Insecure )
870- }
871-
872- return options
873- }
874-
875867// reconcileStorage ensures the current state of the storage matches the
876868// desired and previously observed state.
877869//
@@ -1166,3 +1158,53 @@ func (r *OCIRepositoryReconciler) calculateContentConfigChecksum(obj *sourcev1.O
11661158
11671159 return fmt .Sprintf ("sha256:%x" , sha256 .Sum256 (c ))
11681160}
1161+
1162+ // craneOptions sets the auth headers, timeout and user agent
1163+ // for all operations against remote container registries.
1164+ func craneOptions (ctx context.Context , insecure bool ) []crane.Option {
1165+ options := []crane.Option {
1166+ crane .WithContext (ctx ),
1167+ crane .WithUserAgent (oci .UserAgent ),
1168+ }
1169+
1170+ if insecure {
1171+ options = append (options , crane .Insecure )
1172+ }
1173+
1174+ return options
1175+ }
1176+
1177+ // makeRemoteOptions returns a remoteOptions struct with the authentication and transport options set.
1178+ // The returned struct can be used to interact with a remote registry using go-containerregistry based libraries.
1179+ func makeRemoteOptions (ctxTimeout context.Context , obj * sourcev1.OCIRepository , transport http.RoundTripper ,
1180+ keychain authn.Keychain , auth authn.Authenticator ) remoteOptions {
1181+ o := remoteOptions {
1182+ craneOpts : craneOptions (ctxTimeout , obj .Spec .Insecure ),
1183+ verifyOpts : []remote.Option {},
1184+ }
1185+
1186+ if transport != nil {
1187+ o .craneOpts = append (o .craneOpts , crane .WithTransport (transport ))
1188+ o .verifyOpts = append (o .verifyOpts , remote .WithTransport (transport ))
1189+ }
1190+
1191+ if auth != nil {
1192+ // auth take precedence over keychain here as we expect the caller to set
1193+ // the auth only if it is required.
1194+ o .verifyOpts = append (o .verifyOpts , remote .WithAuth (auth ))
1195+ o .craneOpts = append (o .craneOpts , crane .WithAuth (auth ))
1196+ return o
1197+ }
1198+
1199+ o .verifyOpts = append (o .verifyOpts , remote .WithAuthFromKeychain (keychain ))
1200+ o .craneOpts = append (o .craneOpts , crane .WithAuthFromKeychain (keychain ))
1201+
1202+ return o
1203+ }
1204+
1205+ // remoteOptions contains the options to interact with a remote registry.
1206+ // It can be used to pass options to go-containerregistry based libraries.
1207+ type remoteOptions struct {
1208+ craneOpts []crane.Option
1209+ verifyOpts []remote.Option
1210+ }
0 commit comments