@@ -73,6 +73,8 @@ type context struct {
7373 inputImagesSeen testInputImages
7474 // releases is used to validate references to release images .
7575 releases sets.Set [string ]
76+ // metadata is used for ownership checks (e.g., audience restrictions).
77+ metadata * api.Metadata
7678}
7779
7880// newContext creates a top-level context.
@@ -81,6 +83,7 @@ func newContext(
8183 env api.TestEnvironment ,
8284 releases sets.Set [string ],
8385 inputImagesSeen testInputImages ,
86+ metadata * api.Metadata ,
8487) * context {
8588 return & context {
8689 field : field ,
@@ -89,6 +92,7 @@ func newContext(
8992 leasesSeen : sets .New [string ](),
9093 inputImagesSeen : inputImagesSeen ,
9194 releases : releases ,
95+ metadata : metadata ,
9296 }
9397}
9498
@@ -575,7 +579,7 @@ func (v *Validator) validateTestConfigurationType(
575579 clusterCount ++
576580 validationErrors = append (validationErrors , v .validateClusterProfile (fieldRoot , testConfig .ClusterProfile , metadata )... )
577581 }
578- context := newContext (fieldPath (fieldRoot ), testConfig .Environment , releases , inputImagesSeen )
582+ context := newContext (fieldPath (fieldRoot ), testConfig .Environment , releases , inputImagesSeen , metadata )
579583 validationErrors = append (validationErrors , validateLeases (context .addField ("leases" ), testConfig .Leases )... )
580584 if testConfig .NodeArchitecture != nil {
581585 validationErrors = append (validationErrors , validateNodeArchitecture (fieldRoot , * testConfig .NodeArchitecture ))
@@ -586,7 +590,7 @@ func (v *Validator) validateTestConfigurationType(
586590 }
587591 if testConfig := test .MultiStageTestConfigurationLiteral ; testConfig != nil {
588592 typeCount ++
589- context := newContext (fieldPath (fieldRoot ).addField ("steps" ), testConfig .Environment , releases , inputImagesSeen )
593+ context := newContext (fieldPath (fieldRoot ).addField ("steps" ), testConfig .Environment , releases , inputImagesSeen , metadata )
590594 if testConfig .ClusterProfile != "" {
591595 clusterCount ++
592596 validationErrors = append (validationErrors , v .validateClusterProfile (fieldRoot , testConfig .ClusterProfile , metadata )... )
@@ -695,7 +699,7 @@ func (v *Validator) validateLiteralTestStep(context *context, stage testStage, s
695699 }
696700 ret = append (ret , validateDependencies (string (context .field ), step .Dependencies )... )
697701 ret = append (ret , validateLeases (context .addField ("leases" ), step .Leases )... )
698- ret = append (ret , validateServiceAccountTokens (string (context .field ), step .ServiceAccountTokens )... )
702+ ret = append (ret , v . validateServiceAccountTokens (string (context .field ), step .ServiceAccountTokens , context . metadata )... )
699703 if step .NodeArchitecture != nil {
700704 if err := validateNodeArchitecture (string (context .field ), * step .NodeArchitecture ); err != nil {
701705 ret = append (ret , err )
@@ -943,12 +947,18 @@ func validateLeases(context *context, leases []api.StepLease) (ret []error) {
943947 return
944948}
945949
946- func validateServiceAccountTokens (fieldRoot string , tokens []api.ServiceAccountTokenVolume ) (ret []error ) {
950+ func ( v * Validator ) validateServiceAccountTokens (fieldRoot string , tokens []api.ServiceAccountTokenVolume , metadata * api. Metadata ) (ret []error ) {
947951 mountPaths := sets .New [string ]()
948952 for i , token := range tokens {
949953 fieldPath := fmt .Sprintf ("%s.service_account_tokens[%d]" , fieldRoot , i )
950954 if token .Audience == "" {
951955 ret = append (ret , fmt .Errorf ("%s.audience: must not be empty" , fieldPath ))
956+ } else if v .allowedAudiences != nil {
957+ if details , ok := v .allowedAudiences [token .Audience ]; ok {
958+ if err := verifyAudienceOwnership (details , metadata ); err != nil {
959+ ret = append (ret , err )
960+ }
961+ }
952962 }
953963 if token .MountPath == "" {
954964 ret = append (ret , fmt .Errorf ("%s.mount_path: must not be empty" , fieldPath ))
@@ -964,6 +974,26 @@ func validateServiceAccountTokens(fieldRoot string, tokens []api.ServiceAccountT
964974 return
965975}
966976
977+ // verifyAudienceOwnership checks if metadata's org and repo match those in the
978+ // audience config, verifying if it's one of the owners of the audience.
979+ func verifyAudienceOwnership (audience api.AllowedAudienceDetails , m * api.Metadata ) error {
980+ if m == nil || m .Org == "" {
981+ return nil
982+ }
983+ if len (audience .Owners ) == 0 {
984+ return nil
985+ }
986+ for _ , owner := range audience .Owners {
987+ if owner .Org != m .Org {
988+ continue
989+ }
990+ if owner .Repos == nil || util .Contains (owner .Repos , m .Repo ) {
991+ return nil
992+ }
993+ }
994+ return fmt .Errorf ("%s/%s is not allowed to use service account token audience %q" , m .Org , m .Repo , audience .Audience )
995+ }
996+
967997func validateNodeArchitectureOverrides (fieldRoot string , nodeArchitectureOverrides api.NodeArchitectureOverrides ) error {
968998 for index , arch := range nodeArchitectureOverrides {
969999 if err := arch .Validate (); err != nil {
0 commit comments