From 331de0b32bc9572bc300b1bb29f987adedd8119c Mon Sep 17 00:00:00 2001 From: Jan Rose Date: Wed, 4 Nov 2026 15:39:24 +0000 Subject: [PATCH] List run_as-unsupported resource types in one place Replace the hand-written block per resource type in validateRunAs with a single list of unsupported resource groups. Iterating AllResources keeps the diagnostics in the same order and at the same locations as before. Dashboards stay a per-resource check because only those with embed_credentials set are rejected. Add a test that every supported resource type is classified exactly once in allowList or the unsupported list, so a new type forces a decision. Co-authored-by: Isaac --- .../config/mutator/resourcemutator/run_as.go | 77 ++++++++----------- .../mutator/resourcemutator/run_as_test.go | 17 ++++ 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/bundle/config/mutator/resourcemutator/run_as.go b/bundle/config/mutator/resourcemutator/run_as.go index b946db77235..119d82b0fa2 100644 --- a/bundle/config/mutator/resourcemutator/run_as.go +++ b/bundle/config/mutator/resourcemutator/run_as.go @@ -42,6 +42,16 @@ func reportRunAsNotSupported(resourceType string, location diag.Location, curren }} } +// Resource groups (by plural name) whose API does not support a run_as identity +// different from the deploying user. Dashboards are not listed because only those +// with embed_credentials set are affected; validateRunAs checks them individually. +var runAsUnsupportedResources = []string{ + "model_serving_endpoints", + "quality_monitors", + "data_quality_monitors", + "apps", +} + func validateRunAs(b *bundle.Bundle) diag.Diagnostics { diags := diag.Diagnostics{} @@ -81,55 +91,32 @@ func validateRunAs(b *bundle.Bundle) diag.Diagnostics { } } - // Model serving endpoints do not support run_as in the API. - if len(b.Config.Resources.ModelServingEndpoints) > 0 { - diags = diags.Extend(reportRunAsNotSupported( - "model_serving_endpoints", - b.Config.GetLocation("resources.model_serving_endpoints"), - b.Config.Workspace.CurrentUser.UserName, - identity, - )) - } - - // Monitors do not support run_as in the API. - if len(b.Config.Resources.QualityMonitors) > 0 { - diags = diags.Extend(reportRunAsNotSupported( - "quality_monitors", - b.Config.GetLocation("resources.quality_monitors"), - b.Config.Workspace.CurrentUser.UserName, - identity, - )) - } - - if len(b.Config.Resources.DataQualityMonitors) > 0 { - diags = diags.Extend(reportRunAsNotSupported( - "data_quality_monitors", - b.Config.GetLocation("resources.data_quality_monitors"), - b.Config.Workspace.CurrentUser.UserName, - identity, - )) - } - - // Dashboards do not support run_as in the API. - if len(b.Config.Resources.Dashboards) > 0 { - for key, dashboard := range b.Config.Resources.Dashboards { - if !dashboard.EmbedCredentials { - continue + // Iterate in AllResources order so diagnostics keep a stable order. + for _, group := range b.Config.Resources.AllResources() { + resourceType := group.Description.PluralName + + // Dashboards only reject run_as when embed_credentials is set, so check each one. + if resourceType == "dashboards" { + for key, dashboard := range b.Config.Resources.Dashboards { + if !dashboard.EmbedCredentials { + continue + } + diags = diags.Extend(reportRunAsNotSupported( + "dashboards with embed_credentials set to true", + b.Config.GetLocationOf(structpath.NewPath(nil, "resources", "dashboards", key)), + b.Config.Workspace.CurrentUser.UserName, + identity, + )) } - diags = diags.Extend(reportRunAsNotSupported( - "dashboards with embed_credentials set to true", - b.Config.GetLocationOf(structpath.NewPath(nil, "resources", "dashboards", key)), - b.Config.Workspace.CurrentUser.UserName, - identity, - )) + continue } - } - // Apps do not support run_as in the API. - if len(b.Config.Resources.Apps) > 0 { + if len(group.Resources) == 0 || !slices.Contains(runAsUnsupportedResources, resourceType) { + continue + } diags = diags.Extend(reportRunAsNotSupported( - "apps", - b.Config.GetLocation("resources.apps"), + resourceType, + b.Config.GetLocation("resources."+resourceType), b.Config.Workspace.CurrentUser.UserName, identity, )) diff --git a/bundle/config/mutator/resourcemutator/run_as_test.go b/bundle/config/mutator/resourcemutator/run_as_test.go index a4acdca94bd..fc26d4ed813 100644 --- a/bundle/config/mutator/resourcemutator/run_as_test.go +++ b/bundle/config/mutator/resourcemutator/run_as_test.go @@ -343,6 +343,23 @@ func TestRunAsErrorForUnsupportedResources(t *testing.T) { } } +func TestRunAsSupportListsAreComplete(t *testing.T) { + supported := config.SupportedResources() + + // Every resource type needs an explicit decision: either it accepts a different + // run_as identity (allowList) or it is rejected (runAsUnsupportedResources). + for key := range supported { + inAllowList := slices.Contains(allowList, key) + inUnsupported := slices.Contains(runAsUnsupportedResources, key) + assert.NotEqual(t, inAllowList, inUnsupported, "%s must be in exactly one of allowList or runAsUnsupportedResources", key) + } + + for _, key := range slices.Concat(allowList, runAsUnsupportedResources) { + _, ok := supported[key] + assert.True(t, ok, "%s is listed for run_as but is not a supported resource type", key) + } +} + func TestRunAsNoErrorForSupportedResources(t *testing.T) { base := config.Root{ Workspace: config.Workspace{