@@ -3351,3 +3351,205 @@ func TestComputeConditions(t *testing.T) {
33513351 })
33523352 }
33533353}
3354+
3355+ // TestGetImageAuthSecret_OCIImageWithValidSecret tests that credentials are extracted
3356+ // successfully when an OCI image has a valid auth secret configured.
3357+ func TestGetImageAuthSecret_OCIImageWithValidSecret (t * testing.T ) {
3358+ host := newDefaultHost (t )
3359+ host .Spec .Online = true
3360+ ociAuthSecretName := "oci-auth-secret"
3361+ host .Spec .Image = & metal3api.Image {
3362+ URL : "oci://registry.example.com/repo/image:tag" ,
3363+ OCIAuthSecretName : & ociAuthSecretName ,
3364+ }
3365+
3366+ // Create the OCI auth secret
3367+ ociSecret := createDockerConfigJSONSecretForTest (t , ociAuthSecretName , namespace , map [string ]map [string ]string {
3368+ "registry.example.com" : {
3369+ "username" : "testuser" ,
3370+ "password" : "testpass" ,
3371+ },
3372+ })
3373+
3374+ r := newTestReconciler (t , host , ociSecret )
3375+
3376+ // Manually call getImageAuthSecret to test the function directly
3377+ credentials , err := r .getImageAuthSecret (t .Context (), host , host .Spec .Image )
3378+
3379+ require .NoError (t , err )
3380+ require .NotEmpty (t , credentials , "expected non-empty credentials" )
3381+
3382+ // Verify credentials are base64 encoded and in correct format
3383+ decoded , err := base64 .StdEncoding .DecodeString (credentials )
3384+ require .NoError (t , err )
3385+ assert .Equal (t , "testuser:testpass" , string (decoded ))
3386+ }
3387+
3388+ // TestGetImageAuthSecret_OCIImageWithoutSecret tests that no error occurs
3389+ // when an OCI image does not have an auth secret configured.
3390+ func TestGetImageAuthSecret_OCIImageWithoutSecret (t * testing.T ) {
3391+ host := newDefaultHost (t )
3392+ host .Spec .Online = true
3393+ host .Spec .Image = & metal3api.Image {
3394+ URL : "oci://registry.example.com/repo/image:tag" ,
3395+ // No OCIAuthSecretName set
3396+ }
3397+
3398+ r := newTestReconciler (t , host )
3399+
3400+ credentials , err := r .getImageAuthSecret (t .Context (), host , host .Spec .Image )
3401+
3402+ require .NoError (t , err )
3403+ assert .Empty (t , credentials , "expected empty credentials when no auth secret is configured" )
3404+ }
3405+
3406+ // TestGetImageAuthSecret_OCIImageWithInvalidSecret tests the behavior when
3407+ // the configured auth secret cannot be parsed or doesn't have valid credentials.
3408+ func TestGetImageAuthSecret_OCIImageWithInvalidSecret (t * testing.T ) {
3409+ host := newDefaultHost (t )
3410+ host .Spec .Online = true
3411+ ociAuthSecretName := "invalid-auth-secret"
3412+ host .Spec .Image = & metal3api.Image {
3413+ URL : "oci://registry.example.com/repo/image:tag" ,
3414+ OCIAuthSecretName : & ociAuthSecretName ,
3415+ }
3416+
3417+ // Create an invalid secret (wrong format)
3418+ invalidSecret := & corev1.Secret {
3419+ ObjectMeta : metav1.ObjectMeta {
3420+ Name : ociAuthSecretName ,
3421+ Namespace : namespace ,
3422+ },
3423+ Type : corev1 .SecretTypeDockerConfigJson ,
3424+ Data : map [string ][]byte {
3425+ // Missing proper dockerconfigjson format
3426+ corev1 .DockerConfigJsonKey : []byte (`{"invalid": "json"}` ),
3427+ },
3428+ }
3429+
3430+ r := newTestReconciler (t , host , invalidSecret )
3431+
3432+ credentials , err := r .getImageAuthSecret (t .Context (), host , host .Spec .Image )
3433+
3434+ require .Error (t , err , "expected error for invalid secret" )
3435+ assert .Empty (t , credentials , "expected empty credentials for invalid secret" )
3436+ }
3437+
3438+ // TestGetImageAuthSecret_OCIImageWithMissingSecret tests the behavior when
3439+ // the configured auth secret doesn't exist.
3440+ func TestGetImageAuthSecret_OCIImageWithMissingSecret (t * testing.T ) {
3441+ host := newDefaultHost (t )
3442+ host .Spec .Online = true
3443+ ociAuthSecretName := "nonexistent-secret"
3444+ host .Spec .Image = & metal3api.Image {
3445+ URL : "oci://registry.example.com/repo/image:tag" ,
3446+ OCIAuthSecretName : & ociAuthSecretName ,
3447+ }
3448+
3449+ r := newTestReconciler (t , host )
3450+
3451+ credentials , err := r .getImageAuthSecret (t .Context (), host , host .Spec .Image )
3452+
3453+ require .Error (t , err , "expected error for missing secret" )
3454+ assert .Empty (t , credentials , "expected empty credentials for missing secret" )
3455+ }
3456+
3457+ // TestGetImageAuthSecret_NonOCIImageWithAuthSecret tests that auth secrets
3458+ // are ignored for non-OCI images.
3459+ func TestGetImageAuthSecret_NonOCIImageWithAuthSecret (t * testing.T ) {
3460+ host := newDefaultHost (t )
3461+ host .Spec .Online = true
3462+ ociAuthSecretName := "oci-auth-secret"
3463+ host .Spec .Image = & metal3api.Image {
3464+ URL : "http://example.com/image.qcow2" , // Non-OCI URL
3465+ OCIAuthSecretName : & ociAuthSecretName ,
3466+ }
3467+
3468+ // Create the auth secret even though it shouldn't be used
3469+ ociSecret := createDockerConfigJSONSecretForTest (t , ociAuthSecretName , namespace , map [string ]map [string ]string {
3470+ "registry.example.com" : {
3471+ "username" : "testuser" ,
3472+ "password" : "testpass" ,
3473+ },
3474+ })
3475+
3476+ r := newTestReconciler (t , host , ociSecret )
3477+
3478+ credentials , err := r .getImageAuthSecret (t .Context (), host , host .Spec .Image )
3479+
3480+ require .NoError (t , err )
3481+ assert .Empty (t , credentials , "expected empty credentials for non-OCI image" )
3482+ }
3483+
3484+ // TestGetImageAuthSecret_NilImage tests that the function handles nil image gracefully.
3485+ func TestGetImageAuthSecret_NilImage (t * testing.T ) {
3486+ host := newDefaultHost (t )
3487+ host .Spec .Online = true
3488+ host .Spec .Image = nil
3489+
3490+ r := newTestReconciler (t , host )
3491+
3492+ credentials , err := r .getImageAuthSecret (t .Context (), host , host .Spec .Image )
3493+
3494+ require .NoError (t , err )
3495+ assert .Empty (t , credentials , "expected empty credentials for nil image" )
3496+ }
3497+
3498+ // TestGetImageAuthSecret_RegistryMismatch tests the behavior when the auth secret
3499+ // doesn't contain credentials for the image's registry.
3500+ func TestGetImageAuthSecret_RegistryMismatch (t * testing.T ) {
3501+ host := newDefaultHost (t )
3502+ host .Spec .Online = true
3503+ ociAuthSecretName := "oci-auth-secret"
3504+ host .Spec .Image = & metal3api.Image {
3505+ URL : "oci://registry.example.com/repo/image:tag" ,
3506+ OCIAuthSecretName : & ociAuthSecretName ,
3507+ }
3508+
3509+ // Create secret with credentials for a different registry
3510+ ociSecret := createDockerConfigJSONSecretForTest (t , ociAuthSecretName , namespace , map [string ]map [string ]string {
3511+ "different-registry.com" : {
3512+ "username" : "testuser" ,
3513+ "password" : "testpass" ,
3514+ },
3515+ })
3516+
3517+ r := newTestReconciler (t , host , ociSecret )
3518+
3519+ credentials , err := r .getImageAuthSecret (t .Context (), host , host .Spec .Image )
3520+
3521+ require .Error (t , err , "expected error when registry doesn't match" )
3522+ assert .Empty (t , credentials , "expected empty credentials when registry doesn't match" )
3523+ }
3524+
3525+ // Helper function to create a dockerconfigjson secret for testing.
3526+ func createDockerConfigJSONSecretForTest (t * testing.T , name , ns string , auths map [string ]map [string ]string ) * corev1.Secret {
3527+ t .Helper ()
3528+ dockerAuths := make (map [string ]interface {})
3529+ for registry , creds := range auths {
3530+ username := creds ["username" ]
3531+ password := creds ["password" ]
3532+ // Encode credentials as base64("username:password") in the Auth field
3533+ auth := base64 .StdEncoding .EncodeToString ([]byte (username + ":" + password ))
3534+ dockerAuths [registry ] = map [string ]string {
3535+ "auth" : auth ,
3536+ }
3537+ }
3538+
3539+ dockerConfig := map [string ]interface {}{
3540+ "auths" : dockerAuths ,
3541+ }
3542+ dockerConfigJSON , err := json .Marshal (dockerConfig )
3543+ require .NoError (t , err )
3544+
3545+ return & corev1.Secret {
3546+ ObjectMeta : metav1.ObjectMeta {
3547+ Name : name ,
3548+ Namespace : ns ,
3549+ },
3550+ Type : corev1 .SecretTypeDockerConfigJson ,
3551+ Data : map [string ][]byte {
3552+ corev1 .DockerConfigJsonKey : dockerConfigJSON ,
3553+ },
3554+ }
3555+ }
0 commit comments