diff --git a/bundle/direct/dresources/permissions.go b/bundle/direct/dresources/permissions.go index 0db6449821..eac5e2dcdb 100644 --- a/bundle/direct/dresources/permissions.go +++ b/bundle/direct/dresources/permissions.go @@ -54,6 +54,23 @@ type PermissionsState struct { EmbeddedSlice []StatePermission `json:"__embed__,omitempty"` } +// permissionIDFields maps resource types that use a non-standard ID field for +// the permissions API (most resources use "id"). +var permissionIDFields = map[string]string{ + "model_serving_endpoints": "endpoint_id", // internal numeric ID, not the name used in CRUD APIs + "models": "model_id", // numeric model ID, not the model name used as CRUD state ID + "postgres_projects": "project_id", // bare project_id, not the hierarchical "projects/{id}" state ID + "vector_search_endpoints": "endpoint_uuid", // endpoint UUID, not the endpoint name used as deployment ID +} + +// objectIDRef returns the reference expression for the permissions object ID. +func objectIDRef(prefix, baseNode, resourceType string) string { + if field, ok := permissionIDFields[resourceType]; ok { + return prefix + "${" + baseNode + "." + field + "}" + } + return prefix + "${" + baseNode + ".id}" +} + func PreparePermissionsInputConfig(inputConfig any, node string) (*structvar.StructVar, error) { baseNode, ok := strings.CutSuffix(node, ".permissions") if !ok { @@ -76,39 +93,13 @@ func PreparePermissionsInputConfig(inputConfig any, node string) (*structvar.Str return nil, err } - objectIdRef := prefix + "${" + baseNode + ".id}" - // For permissions, model serving endpoint uses its internal ID, which is different - // from its CRUD APIs which use the name. - // We have a wrapper struct [ModelServingEndpointRemote] from which we read the internal ID - // in order to set the appropriate permissions. - if strings.HasPrefix(baseNode, "resources.model_serving_endpoints.") { - objectIdRef = prefix + "${" + baseNode + ".endpoint_id}" - } - - // MLflow models use the model name as the state ID (for CRUD operations), - // but the permissions API requires the numeric model ID. - if strings.HasPrefix(baseNode, "resources.models.") { - objectIdRef = prefix + "${" + baseNode + ".model_id}" - } - - // Vector search endpoints use the endpoint name as deployment id; the permissions API uses endpoint UUID. - if strings.HasPrefix(baseNode, "resources.vector_search_endpoints.") { - objectIdRef = prefix + "${" + baseNode + ".endpoint_uuid}" - } - - // Postgres projects store their hierarchical name ("projects/{project_id}") as the state ID, - // but the permissions API expects just the project_id. - if strings.HasPrefix(baseNode, "resources.postgres_projects.") { - objectIdRef = prefix + "${" + baseNode + ".project_id}" - } - return &structvar.StructVar{ Value: &PermissionsState{ ObjectID: "", // Always a reference, defined in Refs below EmbeddedSlice: permissions, }, Refs: map[string]string{ - "object_id": objectIdRef, + "object_id": objectIDRef(prefix, baseNode, resourceType), }, }, nil }