Repository: knative/eventing (Go)

Issue:
Support auto generation of PingSource identity service account and expose in `AuthStatus`
**Problem** 

As the [Eventing OIDC feature track](https://docs.google.com/document/d/1e7UgNTkL0Br5Da09Rg2ieVmhKJo4VXuBj-mHT9NCujY/edit#bookmark=id.gvbj3362t2fy) describes, the `AuthStatus` is meant to provide the generated service account name in the resource status.

After #7173 is done, we should:
* when the feature flag (see #7174) is disabled:
  * no change in behavior
* when the feature flag (see #7174) is enabled:
  * create the service account for the PingSource identity
  * expose the service accounts name in `.status.auth.serviceAccountName`


Discussion:
hi @creydr 

I see you've added `help-wanted` label to this issue. If you think this is a good `good-first-issue`, can you:
* Comment with `/good-first-issue`?
* Add clear instructions (including code pointers) about how this issue can be resolved?
/assign
#7299 and #7316 show how this was done for the Trigger and could help to get started with this.
@creydr Thanks for the info!



Patch:
diff --git a/pkg/apis/sources/v1/ping_lifecycle.go b/pkg/apis/sources/v1/ping_lifecycle.go
index 24222d62112..8fa7cea6fae 100644
--- a/pkg/apis/sources/v1/ping_lifecycle.go
+++ b/pkg/apis/sources/v1/ping_lifecycle.go
@@ -35,11 +35,15 @@ const (
 
 	// PingSourceConditionDeployed has status True when the PingSource has had it's receive adapter deployment created.
 	PingSourceConditionDeployed apis.ConditionType = "Deployed"
+
+	// PingSourceConditionOIDCIdentityCreated has status True when the PingSource has had it's OIDC identity created.
+	PingSourceConditionOIDCIdentityCreated apis.ConditionType = "OIDCIdentityCreated"
 )
 
 var PingSourceCondSet = apis.NewLivingConditionSet(
 	PingSourceConditionSinkProvided,
-	PingSourceConditionDeployed)
+	PingSourceConditionDeployed,
+	PingSourceConditionOIDCIdentityCreated)
 
 const (
 	// PingSourceEventType is the default PingSource CloudEvent type.
@@ -122,3 +126,19 @@ func (s *PingSourceStatus) PropagateDeploymentAvailability(d *appsv1.Deployment)
 		PingSourceCondSet.Manage(s).MarkUnknown(PingSourceConditionDeployed, "DeploymentUnavailable", "The Deployment '%s' is unavailable.", d.Name)
 	}
 }
+
+func (s *PingSourceStatus) MarkOIDCIdentityCreatedSucceeded() {
+	PingSourceCondSet.Manage(s).MarkTrue(PingSourceConditionOIDCIdentityCreated)
+}
+
+func (s *PingSourceStatus) MarkOIDCIdentityCreatedSucceededWithReason(reason, messageFormat string, messageA ...interface{}) {
+	PingSourceCondSet.Manage(s).MarkTrueWithReason(PingSourceConditionOIDCIdentityCreated, reason, messageFormat, messageA...)
+}
+
+func (s *PingSourceStatus) MarkOIDCIdentityCreatedFailed(reason, messageFormat string, messageA ...interface{}) {
+	PingSourceCondSet.Manage(s).MarkFalse(PingSourceConditionOIDCIdentityCreated, reason, messageFormat, messageA...)
+}
+
+func (s *PingSourceStatus) MarkOIDCIdentityCreatedUnknown(reason, messageFormat string, messageA ...interface{}) {
+	PingSourceCondSet.Manage(s).MarkUnknown(PingSourceConditionOIDCIdentityCreated, reason, messageFormat, messageA...)
+}
diff --git a/pkg/reconciler/pingsource/controller.go b/pkg/reconciler/pingsource/controller.go
index ff52bad2b0b..724908e6a67 100644
--- a/pkg/reconciler/pingsource/controller.go
+++ b/pkg/reconciler/pingsource/controller.go
@@ -19,6 +19,10 @@ package pingsource
 import (
 	"context"
 
+	sourcesv1 "knative.dev/eventing/pkg/apis/sources/v1"
+
+	serviceaccountinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/serviceaccount"
+
 	"go.uber.org/zap"
 
 	appsv1 "k8s.io/api/apps/v1"
@@ -60,18 +64,26 @@ func NewController(
 		logger.Fatalw("Error converting leader election configuration to JSON", zap.Error(err))
 	}
 
-	featureStore := feature.NewStore(logging.FromContext(ctx).Named("feature-config-store"))
+	var globalResync func(obj interface{})
+
+	featureStore := feature.NewStore(logging.FromContext(ctx).Named("feature-config-store"), func(name string, value interface{}) {
+		if globalResync != nil {
+			globalResync(nil)
+		}
+	})
 	featureStore.WatchConfigs(cmw)
 
 	// Configure the reconciler
 
 	deploymentInformer := deploymentinformer.Get(ctx)
 	pingSourceInformer := pingsourceinformer.Get(ctx)
+	serviceaccountInformer := serviceaccountinformer.Get(ctx)
 
 	r := &Reconciler{
-		kubeClientSet: kubeclient.Get(ctx),
-		leConfig:      leConfig,
-		configAcc:     reconcilersource.WatchConfigurations(ctx, component, cmw),
+		kubeClientSet:        kubeclient.Get(ctx),
+		leConfig:             leConfig,
+		configAcc:            reconcilersource.WatchConfigurations(ctx, component, cmw),
+		serviceAccountLister: serviceaccountInformer.Lister(),
 	}
 
 	impl := pingsourcereconciler.NewImpl(ctx, r, func(impl *controller.Impl) controller.Options {
@@ -80,6 +92,10 @@ func NewController(
 		}
 	})
 
+	globalResync = func(interface{}) {
+		impl.GlobalResync(pingSourceInformer.Informer())
+	}
+
 	r.sinkResolver = resolver.NewURIResolver(ctx, cmw, impl.Tracker)
 
 	pingSourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue))
@@ -97,5 +113,10 @@ func NewController(
 			)),
 	})
 
+	serviceaccountInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
+		FilterFunc: controller.FilterController(&sourcesv1.PingSource{}),
+		Handler:    controller.HandleAll(impl.EnqueueControllerOf),
+	})
+
 	return impl
 }
diff --git a/pkg/reconciler/pingsource/pingsource.go b/pkg/reconciler/pingsource/pingsource.go
index ea1afae131e..1bad1df76f5 100644
--- a/pkg/reconciler/pingsource/pingsource.go
+++ b/pkg/reconciler/pingsource/pingsource.go
@@ -21,6 +21,10 @@ import (
 	"encoding/json"
 	"fmt"
 
+	v1 "k8s.io/client-go/listers/core/v1"
+	"knative.dev/eventing/pkg/apis/feature"
+	"knative.dev/eventing/pkg/auth"
+
 	"go.uber.org/zap"
 
 	appsv1 "k8s.io/api/apps/v1"
@@ -74,6 +78,8 @@ type Reconciler struct {
 
 	// Leader election configuration for the mt receive adapter
 	leConfig string
+
+	serviceAccountLister v1.ServiceAccountLister
 }
 
 // Check that our Reconciler implements ReconcileKind
@@ -99,6 +105,24 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, source *sourcesv1.PingSo
 		}
 	}
 
+	// OIDC authentication
+	featureFlags := feature.FromContext(ctx)
+	if featureFlags.IsOIDCAuthentication() {
+		saName := auth.GetOIDCServiceAccountNameForResource(sourcesv1.SchemeGroupVersion.WithKind("PingSource"), source.ObjectMeta)
+		source.Status.Auth = &duckv1.AuthStatus{
+			ServiceAccountName: &saName,
+		}
+
+		if err := auth.EnsureOIDCServiceAccountExistsForResource(ctx, r.serviceAccountLister, r.kubeClientSet, sourcesv1.SchemeGroupVersion.WithKind("PingSource"), source.ObjectMeta); err != nil {
+			source.Status.MarkOIDCIdentityCreatedFailed("Unable to resolve service account for OIDC authentication", "%v", err)
+			return err
+		}
+		source.Status.MarkOIDCIdentityCreatedSucceeded()
+	} else {
+		source.Status.Auth = nil
+		source.Status.MarkOIDCIdentityCreatedSucceededWithReason(fmt.Sprintf("%s feature disabled", feature.OIDCAuthentication), "")
+	}
+
 	sinkAddr, err := r.sinkResolver.AddressableFromDestinationV1(ctx, *dest, source)
 	if err != nil {
 		source.Status.MarkNoSink("NotFound", "")


Test patch:
diff --git a/pkg/adapter/mtping/pingsource_test.go b/pkg/adapter/mtping/pingsource_test.go
index 8038d018a1b..f3fb45ee129 100644
--- a/pkg/adapter/mtping/pingsource_test.go
+++ b/pkg/adapter/mtping/pingsource_test.go
@@ -89,6 +89,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceDeployed,
 					rtv1.WithPingSourceSink(sinkAddr),
 					rtv1.WithPingSourceCloudEventAttributes,
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			},
 			WantErr: false,
@@ -112,6 +113,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceDeployed,
 					rtv1.WithPingSourceSink(sinkAddr),
 					rtv1.WithPingSourceCloudEventAttributes,
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			},
 			WantErr: false,
@@ -137,6 +139,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceDeployed,
 					rtv1.WithPingSourceSink(sinkAddr),
 					rtv1.WithPingSourceCloudEventAttributes,
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			},
 			WantErr: false,
@@ -162,6 +165,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceDeployed,
 					rtv1.WithPingSourceSink(sinkAddr),
 					rtv1.WithPingSourceCloudEventAttributes,
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			},
 			WantErr: false,
@@ -188,6 +192,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceSink(sinkAddr),
 					rtv1.WithPingSourceCloudEventAttributes,
 					rtv1.WithPingSourceDeleted,
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			},
 			WantErr: false,
@@ -210,6 +215,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceSink(sinkAddr),
 					rtv1.WithPingSourceCloudEventAttributes,
 					rtv1.WithPingSourceDeleted,
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			},
 			WantErr: false,
diff --git a/pkg/apis/sources/v1/ping_lifecycle_test.go b/pkg/apis/sources/v1/ping_lifecycle_test.go
index e01ce800eb7..1c5bd337d26 100644
--- a/pkg/apis/sources/v1/ping_lifecycle_test.go
+++ b/pkg/apis/sources/v1/ping_lifecycle_test.go
@@ -72,6 +72,7 @@ func TestPingSourceStatusIsReady(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			return s
 		}(),
 		wantConditionStatus: corev1.ConditionUnknown,
@@ -81,6 +82,7 @@ func TestPingSourceStatusIsReady(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			s.PropagateDeploymentAvailability(availableDeployment)
 			return s
 		}(),
@@ -91,7 +93,7 @@ func TestPingSourceStatusIsReady(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
-
+			s.MarkOIDCIdentityCreatedSucceeded()
 			s.MarkSink(exampleAddr)
 			return s
 		}(),
@@ -102,16 +104,32 @@ func TestPingSourceStatusIsReady(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			s.MarkSink(exampleAddr)
 			s.PropagateDeploymentAvailability(availableDeployment)
 			return s
 		}(),
 		wantConditionStatus: corev1.ConditionTrue,
 		want:                true,
-	}}
+	},
+		{
+			name: "oidc status false",
+			s: func() *PingSourceStatus {
+				s := &PingSourceStatus{}
+				s.InitializeConditions()
+				s.MarkOIDCIdentityCreatedFailed("Unable to create the OIDC identity", "")
+				s.MarkSink(exampleAddr)
+				s.PropagateDeploymentAvailability(availableDeployment)
+				return s
+			}(),
+			wantConditionStatus: corev1.ConditionFalse,
+			want:                false,
+		},
+	}
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
+
 			if test.wantConditionStatus != "" {
 				gotConditionStatus := test.s.GetTopLevelCondition().Status
 				if gotConditionStatus != test.wantConditionStatus {
@@ -122,6 +140,7 @@ func TestPingSourceStatusIsReady(t *testing.T) {
 			if got != test.want {
 				t.Errorf("unexpected readiness: want %v, got %v", test.want, got)
 			}
+
 		})
 	}
 }
@@ -145,6 +164,7 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			return s
 		}(),
 		want: &apis.Condition{
@@ -156,6 +176,7 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			s.PropagateDeploymentAvailability(availableDeployment)
 			return s
 		}(),
@@ -168,6 +189,7 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			s.MarkSink(exampleAddr)
 			return s
 		}(),
@@ -180,6 +202,7 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			s.MarkSink(exampleAddr)
 			s.PropagateDeploymentAvailability(availableDeployment)
 			return s
@@ -188,10 +211,28 @@ func TestPingSourceStatusGetTopLevelCondition(t *testing.T) {
 			Type:   PingSourceConditionReady,
 			Status: corev1.ConditionTrue,
 		},
-	}}
+	},
+		{
+			name: "oidc fail",
+			s: func() *PingSourceStatus {
+				s := &PingSourceStatus{}
+				s.InitializeConditions()
+				s.MarkOIDCIdentityCreatedFailed("Unable to create the OIDC identity", "")
+				s.MarkSink(exampleAddr)
+				s.PropagateDeploymentAvailability(availableDeployment)
+				return s
+			}(),
+			want: &apis.Condition{
+				Type:   PingSourceConditionReady,
+				Status: corev1.ConditionFalse,
+				Reason: "Unable to create the OIDC identity",
+			},
+		},
+	}
 
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
+
 			got := test.s.GetTopLevelCondition()
 			ignoreTime := cmpopts.IgnoreFields(apis.Condition{},
 				"LastTransitionTime", "Severity")
@@ -223,6 +264,7 @@ func TestPingSourceStatusGetCondition(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			return s
 		}(),
 		condQuery: PingSourceConditionReady,
@@ -235,6 +277,7 @@ func TestPingSourceStatusGetCondition(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			s.PropagateDeploymentAvailability(availableDeployment)
 			return s
 		}(),
@@ -248,6 +291,7 @@ func TestPingSourceStatusGetCondition(t *testing.T) {
 		s: func() *PingSourceStatus {
 			s := &PingSourceStatus{}
 			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedSucceeded()
 			s.MarkSink(exampleAddr)
 			return s
 		}(),
@@ -256,6 +300,21 @@ func TestPingSourceStatusGetCondition(t *testing.T) {
 			Type:   PingSourceConditionReady,
 			Status: corev1.ConditionUnknown,
 		},
+	}, {
+		name: "oidc failed",
+		s: func() *PingSourceStatus {
+			s := &PingSourceStatus{}
+			s.InitializeConditions()
+			s.MarkOIDCIdentityCreatedFailed("Unable to create the OIDC identity", "")
+			s.MarkSink(exampleAddr)
+			return s
+		}(),
+		condQuery: PingSourceConditionReady,
+		want: &apis.Condition{
+			Type:   PingSourceConditionReady,
+			Status: corev1.ConditionFalse,
+			Reason: "Unable to create the OIDC identity",
+		},
 	}}
 
 	for _, test := range tests {
diff --git a/pkg/reconciler/pingsource/pingsource_test.go b/pkg/reconciler/pingsource/pingsource_test.go
index d2c099983f6..4e84a050926 100644
--- a/pkg/reconciler/pingsource/pingsource_test.go
+++ b/pkg/reconciler/pingsource/pingsource_test.go
@@ -18,9 +18,13 @@ package pingsource
 
 import (
 	"context"
+	"fmt"
 	"os"
 	"testing"
 
+	"knative.dev/eventing/pkg/apis/feature"
+	"knative.dev/eventing/pkg/auth"
+
 	cloudevents "github.com/cloudevents/sdk-go/v2"
 	"k8s.io/utils/pointer"
 
@@ -141,6 +145,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithInitPingSourceConditions,
 					rtv1.WithPingSourceStatusObservedGeneration(generation),
 					rtv1.WithPingSourceSinkNotFound,
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			}},
 			WantEvents: []string{
@@ -184,6 +189,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithInitPingSourceConditions,
 					rtv1.WithPingSourceStatusObservedGeneration(generation),
 					rtv1.WithPingSourceSinkNotFound,
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			}},
 			WantEvents: []string{
@@ -239,6 +245,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithInitPingSourceConditions,
 					rtv1.WithPingSourceSink(sinkAddressable),
 					rtv1.WithPingSourceStatusObservedGeneration(generation),
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			}},
 		}, {
@@ -281,6 +288,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceSink(sinkAddressable),
 					rtv1.WithPingSourceCloudEventAttributes,
 					rtv1.WithPingSourceStatusObservedGeneration(generation),
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			}},
 			WantEvents: []string{
@@ -337,6 +345,7 @@ func TestAllCases(t *testing.T) {
 					}),
 					rtv1.WithPingSourceCloudEventAttributes,
 					rtv1.WithPingSourceStatusObservedGeneration(generation),
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			}},
 			WantEvents: []string{
@@ -392,6 +401,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceSink(sinkAddressable),
 					rtv1.WithPingSourceCloudEventAttributes,
 					rtv1.WithPingSourceStatusObservedGeneration(generation),
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			}},
 			WantUpdates: []clientgotesting.UpdateActionImpl{{
@@ -437,6 +447,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceSink(sinkAddressable),
 					rtv1.WithPingSourceCloudEventAttributes,
 					rtv1.WithPingSourceStatusObservedGeneration(generation),
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			}},
 			WantEvents: []string{
@@ -485,6 +496,7 @@ func TestAllCases(t *testing.T) {
 					rtv1.WithPingSourceSink(sinkAddressable),
 					rtv1.WithPingSourceCloudEventAttributes,
 					rtv1.WithPingSourceStatusObservedGeneration(generation),
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled(),
 				),
 			}},
 			WantEvents: []string{
@@ -494,15 +506,127 @@ func TestAllCases(t *testing.T) {
 				patchFinalizers(sourceName, testNS),
 			},
 		},
+		{
+			Name: "OIDC: creates OIDC service account",
+			Ctx: feature.ToContext(context.Background(), feature.Flags{
+				feature.OIDCAuthentication: feature.Enabled,
+			}),
+			Objects: []runtime.Object{
+				rtv1.NewPingSource(sourceName, testNS,
+					rtv1.WithPingSourceSpec(sourcesv1.PingSourceSpec{
+						Schedule:    testSchedule,
+						ContentType: testContentType,
+						Data:        testData,
+						SourceSpec: duckv1.SourceSpec{
+							Sink: sinkDest,
+						},
+					}),
+					rtv1.WithPingSource(sourceUID),
+					rtv1.WithPingSourceObjectMetaGeneration(generation),
+				),
+				rtv1.NewChannel(sinkName, testNS,
+					rtv1.WithInitChannelConditions,
+					rtv1.WithChannelAddress(sinkAddressable),
+				),
+				makeAvailableMTAdapter(),
+			},
+			Key: testNS + "/" + sourceName,
+			WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
+				Object: rtv1.NewPingSource(sourceName, testNS,
+					rtv1.WithPingSourceSpec(sourcesv1.PingSourceSpec{
+						Schedule:    testSchedule,
+						ContentType: testContentType,
+						Data:        testData,
+						SourceSpec: duckv1.SourceSpec{
+							Sink: sinkDest,
+						},
+					}),
+					rtv1.WithPingSource(sourceUID),
+					rtv1.WithPingSourceObjectMetaGeneration(generation),
+					// Status Update:
+					rtv1.WithInitPingSourceConditions,
+					rtv1.WithPingSourceDeployed,
+					rtv1.WithPingSourceSink(sinkAddressable),
+					rtv1.WithPingSourceCloudEventAttributes,
+					rtv1.WithPingSourceStatusObservedGeneration(generation),
+					rtv1.WithPingSourceOIDCIdentityCreatedSucceeded(),
+					rtv1.WithPingSourceOIDCServiceAccountName(makePingSourceOIDCServiceAccount().Name),
+				),
+			}},
+			WantCreates: []runtime.Object{
+				makePingSourceOIDCServiceAccount(),
+			},
+			WantEvents: []string{
+				Eventf(corev1.EventTypeNormal, "FinalizerUpdate", "Updated %q finalizers", sourceName),
+			},
+			WantPatches: []clientgotesting.PatchActionImpl{
+				patchFinalizers(sourceName, testNS),
+			},
+		},
+		{
+			Name: "OIDC: PingSource not ready on invalid OIDC service account",
+			Ctx: feature.ToContext(context.Background(), feature.Flags{
+				feature.OIDCAuthentication: feature.Enabled,
+			}),
+			Objects: []runtime.Object{
+				makePingSourceOIDCServiceAccountWithoutOwnerRef(),
+				rtv1.NewPingSource(sourceName, testNS,
+					rtv1.WithPingSourceSpec(sourcesv1.PingSourceSpec{
+						Schedule:    testSchedule,
+						ContentType: testContentType,
+						Data:        testData,
+						SourceSpec: duckv1.SourceSpec{
+							Sink: sinkDest,
+						},
+					}),
+					rtv1.WithPingSource(sourceUID),
+					rtv1.WithPingSourceObjectMetaGeneration(generation),
+				),
+				rtv1.NewChannel(sinkName, testNS,
+					rtv1.WithInitChannelConditions,
+					rtv1.WithChannelAddress(sinkAddressable),
+				),
+				makeAvailableMTAdapter(),
+			},
+			Key: testNS + "/" + sourceName,
+			WantStatusUpdates: []clientgotesting.UpdateActionImpl{{
+				Object: rtv1.NewPingSource(sourceName, testNS,
+					rtv1.WithPingSourceSpec(sourcesv1.PingSourceSpec{
+						Schedule:    testSchedule,
+						ContentType: testContentType,
+						Data:        testData,
+						SourceSpec: duckv1.SourceSpec{
+							Sink: sinkDest,
+						},
+					}),
+					rtv1.WithPingSource(sourceUID),
+					rtv1.WithPingSourceObjectMetaGeneration(generation),
+					// Status Update:
+					rtv1.WithInitPingSourceConditions,
+					rtv1.WithPingSourceStatusObservedGeneration(generation),
+					rtv1.WithPingSourceOIDCIdentityCreatedFailed("Unable to resolve service account for OIDC authentication", fmt.Sprintf("service account %s not owned by PingSource %s", makePingSourceOIDCServiceAccountWithoutOwnerRef().Name, sourceName)),
+					rtv1.WithPingSourceOIDCServiceAccountName(makePingSourceOIDCServiceAccount().Name),
+				),
+			}},
+			WantErr: true,
+			WantEvents: []string{
+				Eventf(corev1.EventTypeNormal, "FinalizerUpdate", "Updated %q finalizers", sourceName),
+				Eventf(corev1.EventTypeWarning, "InternalError", fmt.Sprintf("service account %s not owned by PingSource %s", makePingSourceOIDCServiceAccountWithoutOwnerRef().Name, sourceName)),
+			},
+			WantPatches: []clientgotesting.PatchActionImpl{
+				patchFinalizers(sourceName, testNS),
+			},
+		},
 	}
 
 	logger := logtesting.TestLogger(t)
 	table.Test(t, rtv1.MakeFactory(func(ctx context.Context, listers *rtv1.Listers, cmw configmap.Watcher) controller.Reconciler {
 		ctx = addressable.WithDuck(ctx)
 		r := &Reconciler{
-			configAcc:     &reconcilersource.EmptyVarsGenerator{},
-			kubeClientSet: fakekubeclient.Get(ctx),
-			tracker:       tracker.New(func(types.NamespacedName) {}, 0),
+			configAcc:            &reconcilersource.EmptyVarsGenerator{},
+			kubeClientSet:        fakekubeclient.Get(ctx),
+			tracker:              tracker.New(func(types.NamespacedName) {}, 0),
+			serviceAccountLister: listers.GetServiceAccountLister(),
 		}
 		r.sinkResolver = resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0))
 
@@ -561,3 +685,22 @@ func patchFinalizers(name, namespace string) clientgotesting.PatchActionImpl {
 	action.Patch = []byte(patch)
 	return action
 }
+
+func makePingSourceOIDCServiceAccount() *corev1.ServiceAccount {
+	return auth.GetOIDCServiceAccountForResource(sourcesv1.SchemeGroupVersion.WithKind("PingSource"), metav1.ObjectMeta{
+		Name:      sourceName,
+		Namespace: testNS,
+		UID:       sourceUID,
+	})
+}
+
+func makePingSourceOIDCServiceAccountWithoutOwnerRef() *corev1.ServiceAccount {
+	sa := auth.GetOIDCServiceAccountForResource(sourcesv1.SchemeGroupVersion.WithKind("PingSource"), metav1.ObjectMeta{
+		Name:      sourceName,
+		Namespace: testNS,
+		UID:       sourceUID,
+	})
+	sa.OwnerReferences = nil
+
+	return sa
+}
diff --git a/pkg/reconciler/testing/v1/pingsource.go b/pkg/reconciler/testing/v1/pingsource.go
index 86ae5b329f4..e930ed46027 100644
--- a/pkg/reconciler/testing/v1/pingsource.go
+++ b/pkg/reconciler/testing/v1/pingsource.go
@@ -18,8 +18,11 @@ package testing
 
 import (
 	"context"
+	"fmt"
 	"time"
 
+	"knative.dev/eventing/pkg/apis/feature"
+
 	"knative.dev/eventing/pkg/reconciler/testing"
 
 	duckv1 "knative.dev/pkg/apis/duck/v1"
@@ -107,3 +110,31 @@ func WithPingSourceDeleted(c *v1.PingSource) {
 	t := metav1.NewTime(time.Unix(1e9, 0))
 	c.SetDeletionTimestamp(&t)
 }
+
+func WithPingSourceOIDCIdentityCreatedSucceeded() PingSourceOption {
+	return func(c *v1.PingSource) {
+		c.Status.MarkOIDCIdentityCreatedSucceeded()
+	}
+}
+
+func WithPingSourceOIDCIdentityCreatedSucceededBecauseOIDCFeatureDisabled() PingSourceOption {
+	return func(c *v1.PingSource) {
+		c.Status.MarkOIDCIdentityCreatedSucceededWithReason(fmt.Sprintf("%s feature disabled", feature.OIDCAuthentication), "")
+	}
+}
+
+func WithPingSourceOIDCIdentityCreatedFailed(reason, message string) PingSourceOption {
+	return func(c *v1.PingSource) {
+		c.Status.MarkOIDCIdentityCreatedFailed(reason, message)
+	}
+}
+
+func WithPingSourceOIDCServiceAccountName(name string) PingSourceOption {
+	return func(c *v1.PingSource) {
+		if c.Status.Auth == nil {
+			c.Status.Auth = &duckv1.AuthStatus{}
+		}
+
+		c.Status.Auth.ServiceAccountName = &name
+	}
+}