From 26496cf00ed82d40089c2e45526f51b501d0ecc0 Mon Sep 17 00:00:00 2001 From: Alex Khakhlyuk Date: Fri, 4 Sep 2026 15:30:44 +0000 Subject: [PATCH 1/3] Add grants support for AI Gateway securables (model_service, mcp_service, model_provider_service) Follow-up to the #6410 split. Wires UC grants (the `grants` field + `.grants` sub-resource) into all three AI Gateway securables, mirroring volumes/registered_models: the `Grants` field on each resource config, the resource->securable_type mapping (model_service/mcp_service/ model_provider_service), and the direct-engine grants sub-resource registration. Stacked on the model_provider_service branch. Co-authored-by: Isaac --- .nextchanges/bundles/ai-gateway-grants.md | 1 + .../invariant/configs/mcp_service.yml.tmpl | 4 + .../configs/model_provider_service.yml.tmpl | 4 + .../invariant/configs/model_service.yml.tmpl | 4 + acceptance/bundle/refschema/out.fields.txt | 18 +++ .../grants/mcp_services/databricks.yml.tmpl | 12 ++ .../out.deploy1.requests.direct.json | 17 +++ .../out.destroy.requests.direct.json | 0 .../grants/mcp_services/out.plan1.direct.json | 42 +++++++ .../grants/mcp_services/out.test.toml | 3 + .../resources/grants/mcp_services/output.txt | 35 ++++++ .../resources/grants/mcp_services/script | 12 ++ .../resources/grants/mcp_services/test.toml | 5 + .../databricks.yml.tmpl | 23 ++++ .../out.deploy1.requests.direct.json | 17 +++ .../out.destroy.requests.direct.json | 0 .../out.plan1.direct.json | 61 +++++++++ .../model_provider_services/out.test.toml | 3 + .../grants/model_provider_services/output.txt | 35 ++++++ .../grants/model_provider_services/script | 12 ++ .../grants/model_provider_services/test.toml | 5 + .../grants/model_services/databricks.yml.tmpl | 12 ++ .../out.deploy1.requests.direct.json | 17 +++ .../out.destroy.requests.direct.json | 0 .../model_services/out.plan1.direct.json | 42 +++++++ .../grants/model_services/out.test.toml | 3 + .../grants/model_services/output.txt | 35 ++++++ .../resources/grants/model_services/script | 12 ++ .../resources/grants/model_services/test.toml | 5 + bundle/config/resources/mcp_service.go | 6 + .../resources/model_provider_service.go | 6 + bundle/config/resources/model_service.go | 6 + bundle/direct/dresources/all.go | 17 +-- bundle/direct/dresources/all_test.go | 33 +++++ bundle/direct/dresources/grants.go | 17 +-- bundle/internal/schema/annotations.yml | 15 +++ .../validation/generated/enum_fields.go | 3 + bundle/schema/jsonschema.json | 9 ++ .../bundles/mcp_services/__init__.py | 11 ++ .../mcp_services/_models/mcp_service.py | 21 +++- .../_models/mcp_service_config.py | 5 +- .../bundles/mcp_services/_models/privilege.py | 116 ++++++++++++++++++ .../_models/privilege_assignment.py | 53 ++++++++ .../model_provider_services/__init__.py | 14 +++ .../_models/model_provider_service.py | 16 ++- .../_models/privilege.py | 116 ++++++++++++++++++ .../_models/privilege_assignment.py | 56 +++++++++ .../bundles/model_services/__init__.py | 22 ++++ .../model_services/_models/model_service.py | 16 ++- .../model_services/_models/privilege.py | 116 ++++++++++++++++++ .../_models/privilege_assignment.py | 56 +++++++++ .../core/_generated/mcp_services.py | 5 + .../_generated/model_provider_services.py | 5 + .../core/_generated/model_services.py | 5 + 54 files changed, 1162 insertions(+), 22 deletions(-) create mode 100644 .nextchanges/bundles/ai-gateway-grants.md create mode 100644 acceptance/bundle/resources/grants/mcp_services/databricks.yml.tmpl create mode 100644 acceptance/bundle/resources/grants/mcp_services/out.deploy1.requests.direct.json create mode 100644 acceptance/bundle/resources/grants/mcp_services/out.destroy.requests.direct.json create mode 100644 acceptance/bundle/resources/grants/mcp_services/out.plan1.direct.json create mode 100644 acceptance/bundle/resources/grants/mcp_services/out.test.toml create mode 100644 acceptance/bundle/resources/grants/mcp_services/output.txt create mode 100644 acceptance/bundle/resources/grants/mcp_services/script create mode 100644 acceptance/bundle/resources/grants/mcp_services/test.toml create mode 100644 acceptance/bundle/resources/grants/model_provider_services/databricks.yml.tmpl create mode 100644 acceptance/bundle/resources/grants/model_provider_services/out.deploy1.requests.direct.json create mode 100644 acceptance/bundle/resources/grants/model_provider_services/out.destroy.requests.direct.json create mode 100644 acceptance/bundle/resources/grants/model_provider_services/out.plan1.direct.json create mode 100644 acceptance/bundle/resources/grants/model_provider_services/out.test.toml create mode 100644 acceptance/bundle/resources/grants/model_provider_services/output.txt create mode 100644 acceptance/bundle/resources/grants/model_provider_services/script create mode 100644 acceptance/bundle/resources/grants/model_provider_services/test.toml create mode 100644 acceptance/bundle/resources/grants/model_services/databricks.yml.tmpl create mode 100644 acceptance/bundle/resources/grants/model_services/out.deploy1.requests.direct.json create mode 100644 acceptance/bundle/resources/grants/model_services/out.destroy.requests.direct.json create mode 100644 acceptance/bundle/resources/grants/model_services/out.plan1.direct.json create mode 100644 acceptance/bundle/resources/grants/model_services/out.test.toml create mode 100644 acceptance/bundle/resources/grants/model_services/output.txt create mode 100644 acceptance/bundle/resources/grants/model_services/script create mode 100644 acceptance/bundle/resources/grants/model_services/test.toml create mode 100644 python/databricks/bundles/mcp_services/_models/privilege.py create mode 100644 python/databricks/bundles/mcp_services/_models/privilege_assignment.py create mode 100644 python/databricks/bundles/model_provider_services/_models/privilege.py create mode 100644 python/databricks/bundles/model_provider_services/_models/privilege_assignment.py create mode 100644 python/databricks/bundles/model_services/_models/privilege.py create mode 100644 python/databricks/bundles/model_services/_models/privilege_assignment.py diff --git a/.nextchanges/bundles/ai-gateway-grants.md b/.nextchanges/bundles/ai-gateway-grants.md new file mode 100644 index 00000000000..c8130bbcd8f --- /dev/null +++ b/.nextchanges/bundles/ai-gateway-grants.md @@ -0,0 +1 @@ +* Add grants support for the AI Gateway `model_service`, `mcp_service`, and `model_provider_service` resources (direct engine). ([#6635](https://github.com/databricks/cli/pull/6635)) diff --git a/acceptance/bundle/invariant/configs/mcp_service.yml.tmpl b/acceptance/bundle/invariant/configs/mcp_service.yml.tmpl index 4b463bc5b78..5bf705e853c 100644 --- a/acceptance/bundle/invariant/configs/mcp_service.yml.tmpl +++ b/acceptance/bundle/invariant/configs/mcp_service.yml.tmpl @@ -7,3 +7,7 @@ resources: parent: schemas/main.default mcp_service_id: test-mcp-service-$UNIQUE_NAME comment: test mcp service + grants: + - principal: account users + privileges: + - APPLY_TAG diff --git a/acceptance/bundle/invariant/configs/model_provider_service.yml.tmpl b/acceptance/bundle/invariant/configs/model_provider_service.yml.tmpl index 2c7b0910021..907bdc0b79b 100644 --- a/acceptance/bundle/invariant/configs/model_provider_service.yml.tmpl +++ b/acceptance/bundle/invariant/configs/model_provider_service.yml.tmpl @@ -7,6 +7,10 @@ resources: parent: schemas/main.default model_provider_service_id: test-model-provider-service-$UNIQUE_NAME comment: test model provider service + grants: + - principal: account users + privileges: + - APPLY_TAG config: provider_type: EXTERNAL_MODEL_PROVIDER_TYPE_CUSTOM targets: diff --git a/acceptance/bundle/invariant/configs/model_service.yml.tmpl b/acceptance/bundle/invariant/configs/model_service.yml.tmpl index e4ea6c39dc8..922a813bd88 100644 --- a/acceptance/bundle/invariant/configs/model_service.yml.tmpl +++ b/acceptance/bundle/invariant/configs/model_service.yml.tmpl @@ -7,3 +7,7 @@ resources: parent: schemas/main.default model_service_id: test-model-service-$UNIQUE_NAME comment: test model service + grants: + - principal: account users + privileges: + - APPLY_TAG diff --git a/acceptance/bundle/refschema/out.fields.txt b/acceptance/bundle/refschema/out.fields.txt index faadf3d8dbe..5e774e1b580 100644 --- a/acceptance/bundle/refschema/out.fields.txt +++ b/acceptance/bundle/refschema/out.fields.txt @@ -2103,6 +2103,12 @@ resources.mcp_services.*.mcp_service_id string ALL resources.mcp_services.*.modified_status string INPUT resources.mcp_services.*.parent string ALL resources.mcp_services.*.url string INPUT +resources.mcp_services.*.grants.full_name string ALL +resources.mcp_services.*.grants.securable_type string ALL +resources.mcp_services.*.grants[*] catalog.PrivilegeAssignment ALL +resources.mcp_services.*.grants[*].principal string ALL +resources.mcp_services.*.grants[*].privileges []catalog.Privilege ALL +resources.mcp_services.*.grants[*].privileges[*] catalog.Privilege ALL resources.model_provider_services.*.comment string ALL resources.model_provider_services.*.config *catalog.ModelProviderServiceConfig ALL resources.model_provider_services.*.config.allow_all_targets bool ALL @@ -2189,6 +2195,12 @@ resources.model_provider_services.*.model_provider_service_id string ALL resources.model_provider_services.*.modified_status string INPUT resources.model_provider_services.*.parent string ALL resources.model_provider_services.*.url string INPUT +resources.model_provider_services.*.grants.full_name string ALL +resources.model_provider_services.*.grants.securable_type string ALL +resources.model_provider_services.*.grants[*] catalog.PrivilegeAssignment ALL +resources.model_provider_services.*.grants[*].principal string ALL +resources.model_provider_services.*.grants[*].privileges []catalog.Privilege ALL +resources.model_provider_services.*.grants[*].privileges[*] catalog.Privilege ALL resources.model_services.*.comment string ALL resources.model_services.*.config *catalog.ModelServiceConfig ALL resources.model_services.*.config.inference_table *catalog.InferenceTableConfig ALL @@ -2246,6 +2258,12 @@ resources.model_services.*.model_service_id string ALL resources.model_services.*.modified_status string INPUT resources.model_services.*.parent string ALL resources.model_services.*.url string INPUT +resources.model_services.*.grants.full_name string ALL +resources.model_services.*.grants.securable_type string ALL +resources.model_services.*.grants[*] catalog.PrivilegeAssignment ALL +resources.model_services.*.grants[*].principal string ALL +resources.model_services.*.grants[*].privileges []catalog.Privilege ALL +resources.model_services.*.grants[*].privileges[*] catalog.Privilege ALL resources.model_serving_endpoints.*.ai_gateway *serving.AiGatewayConfig ALL resources.model_serving_endpoints.*.ai_gateway.fallback_config *serving.FallbackConfig ALL resources.model_serving_endpoints.*.ai_gateway.fallback_config.enabled bool ALL diff --git a/acceptance/bundle/resources/grants/mcp_services/databricks.yml.tmpl b/acceptance/bundle/resources/grants/mcp_services/databricks.yml.tmpl new file mode 100644 index 00000000000..57a4a6fab25 --- /dev/null +++ b/acceptance/bundle/resources/grants/mcp_services/databricks.yml.tmpl @@ -0,0 +1,12 @@ +bundle: + name: deploy-mcp-service-grants-$UNIQUE_NAME + +resources: + mcp_services: + my_mcp_service: + parent: schemas/main.myschema + mcp_service_id: myservice + comment: mycomment + grants: + - principal: deco-test-user@databricks.com + privileges: ["APPLY_TAG"] diff --git a/acceptance/bundle/resources/grants/mcp_services/out.deploy1.requests.direct.json b/acceptance/bundle/resources/grants/mcp_services/out.deploy1.requests.direct.json new file mode 100644 index 00000000000..6e62d295a5b --- /dev/null +++ b/acceptance/bundle/resources/grants/mcp_services/out.deploy1.requests.direct.json @@ -0,0 +1,17 @@ +{ + "method": "PATCH", + "path": "/api/2.1/unity-catalog/permissions/mcp_service/main.myschema.myservice", + "body": { + "changes": [ + { + "add": [ + "APPLY_TAG" + ], + "principal": "deco-test-user@databricks.com", + "remove": [ + "ALL_PRIVILEGES" + ] + } + ] + } +} diff --git a/acceptance/bundle/resources/grants/mcp_services/out.destroy.requests.direct.json b/acceptance/bundle/resources/grants/mcp_services/out.destroy.requests.direct.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/acceptance/bundle/resources/grants/mcp_services/out.plan1.direct.json b/acceptance/bundle/resources/grants/mcp_services/out.plan1.direct.json new file mode 100644 index 00000000000..9150113092f --- /dev/null +++ b/acceptance/bundle/resources/grants/mcp_services/out.plan1.direct.json @@ -0,0 +1,42 @@ +{ + "plan_version": [PLAN_VERSION], + "cli_version": "[CLI_VERSION]", + "plan": { + "resources.mcp_services.my_mcp_service": { + "action": "create", + "new_state": { + "value": { + "comment": "mycomment", + "mcp_service_id": "myservice", + "parent": "schemas/main.myschema" + } + } + }, + "resources.mcp_services.my_mcp_service.grants": { + "depends_on": [ + { + "node": "resources.mcp_services.my_mcp_service", + "label": "${resources.mcp_services.my_mcp_service.id}" + } + ], + "action": "create", + "new_state": { + "value": { + "securable_type": "mcp_service", + "full_name": "", + "__embed__": [ + { + "principal": "deco-test-user@databricks.com", + "privileges": [ + "APPLY_TAG" + ] + } + ] + }, + "vars": { + "full_name": "${resources.mcp_services.my_mcp_service.id}" + } + } + } + } +} diff --git a/acceptance/bundle/resources/grants/mcp_services/out.test.toml b/acceptance/bundle/resources/grants/mcp_services/out.test.toml new file mode 100644 index 00000000000..59b56a2037c --- /dev/null +++ b/acceptance/bundle/resources/grants/mcp_services/out.test.toml @@ -0,0 +1,3 @@ +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/resources/grants/mcp_services/output.txt b/acceptance/bundle/resources/grants/mcp_services/output.txt new file mode 100644 index 00000000000..f3bd1e61625 --- /dev/null +++ b/acceptance/bundle/resources/grants/mcp_services/output.txt @@ -0,0 +1,35 @@ + +>>> [CLI] bundle plan -o json + +>>> print_requests.py --get //permissions + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-mcp-service-grants-[UNIQUE_NAME]/default/files... +Created mcp_services.my_mcp_service +Created mcp_services.my_mcp_service.grants +Files: 7 uploaded, 0 deleted +Resources: 2 created, 0 changed, 0 deleted, 0 unchanged + +>>> print_requests.py //permissions + +>>> [CLI] grants get mcp_service main.myschema.myservice +{ + "privilege_assignments": [ + { + "principal": "deco-test-user@databricks.com", + "privileges": [ + "APPLY_TAG" + ] + } + ] +} + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.mcp_services.my_mcp_service + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-mcp-service-grants-[UNIQUE_NAME]/default + +Destroy: 1 deleted + +>>> print_requests.py //permissions diff --git a/acceptance/bundle/resources/grants/mcp_services/script b/acceptance/bundle/resources/grants/mcp_services/script new file mode 100644 index 00000000000..e52883f3522 --- /dev/null +++ b/acceptance/bundle/resources/grants/mcp_services/script @@ -0,0 +1,12 @@ +envsubst < databricks.yml.tmpl > databricks.yml + +trace $CLI bundle plan -o json | jq 'del(.features)' > out.plan1.$DATABRICKS_BUNDLE_ENGINE.json +trace print_requests.py --get //permissions +trace $CLI bundle deploy +trace print_requests.py //permissions > out.deploy1.requests.$DATABRICKS_BUNDLE_ENGINE.json + +# Assert the end result: the grant is applied on the MCP service securable. +trace $CLI grants get mcp_service main.myschema.myservice | jq --sort-keys + +trace $CLI bundle destroy --auto-approve +trace print_requests.py //permissions > out.destroy.requests.$DATABRICKS_BUNDLE_ENGINE.json diff --git a/acceptance/bundle/resources/grants/mcp_services/test.toml b/acceptance/bundle/resources/grants/mcp_services/test.toml new file mode 100644 index 00000000000..439e55ce050 --- /dev/null +++ b/acceptance/bundle/resources/grants/mcp_services/test.toml @@ -0,0 +1,5 @@ +# AI Gateway securables are direct-engine only (no Terraform provider path), so +# there is no direct-vs-terraform request divergence to reconcile on cloud; +# compare the recorded requests locally instead. +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/resources/grants/model_provider_services/databricks.yml.tmpl b/acceptance/bundle/resources/grants/model_provider_services/databricks.yml.tmpl new file mode 100644 index 00000000000..a63044ba962 --- /dev/null +++ b/acceptance/bundle/resources/grants/model_provider_services/databricks.yml.tmpl @@ -0,0 +1,23 @@ +bundle: + name: deploy-model-provider-service-grants-$UNIQUE_NAME + +resources: + model_provider_services: + my_model_provider_service: + parent: schemas/main.myschema + model_provider_service_id: myservice + comment: mycomment + config: + provider_type: EXTERNAL_MODEL_PROVIDER_TYPE_CUSTOM + targets: + - model: gpt-4o + native_api_types: + - openai/v1/chat/completions + custom: + direct: + base_url: https://api.example.com/v1 + api_key: + plaintext: dummy-api-key + grants: + - principal: deco-test-user@databricks.com + privileges: ["APPLY_TAG"] diff --git a/acceptance/bundle/resources/grants/model_provider_services/out.deploy1.requests.direct.json b/acceptance/bundle/resources/grants/model_provider_services/out.deploy1.requests.direct.json new file mode 100644 index 00000000000..afcc75cc24f --- /dev/null +++ b/acceptance/bundle/resources/grants/model_provider_services/out.deploy1.requests.direct.json @@ -0,0 +1,17 @@ +{ + "method": "PATCH", + "path": "/api/2.1/unity-catalog/permissions/model_provider_service/main.myschema.myservice", + "body": { + "changes": [ + { + "add": [ + "APPLY_TAG" + ], + "principal": "deco-test-user@databricks.com", + "remove": [ + "ALL_PRIVILEGES" + ] + } + ] + } +} diff --git a/acceptance/bundle/resources/grants/model_provider_services/out.destroy.requests.direct.json b/acceptance/bundle/resources/grants/model_provider_services/out.destroy.requests.direct.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/acceptance/bundle/resources/grants/model_provider_services/out.plan1.direct.json b/acceptance/bundle/resources/grants/model_provider_services/out.plan1.direct.json new file mode 100644 index 00000000000..9c7ead61585 --- /dev/null +++ b/acceptance/bundle/resources/grants/model_provider_services/out.plan1.direct.json @@ -0,0 +1,61 @@ +{ + "plan_version": [PLAN_VERSION], + "cli_version": "[CLI_VERSION]", + "plan": { + "resources.model_provider_services.my_model_provider_service": { + "action": "create", + "new_state": { + "value": { + "comment": "mycomment", + "config": { + "custom": { + "direct": { + "api_key": { + "plaintext": "dummy-api-key" + }, + "base_url": "https://api.example.com/v1" + } + }, + "provider_type": "EXTERNAL_MODEL_PROVIDER_TYPE_CUSTOM", + "targets": [ + { + "model": "gpt-4o", + "native_api_types": [ + "openai/v1/chat/completions" + ] + } + ] + }, + "model_provider_service_id": "myservice", + "parent": "schemas/main.myschema" + } + } + }, + "resources.model_provider_services.my_model_provider_service.grants": { + "depends_on": [ + { + "node": "resources.model_provider_services.my_model_provider_service", + "label": "${resources.model_provider_services.my_model_provider_service.id}" + } + ], + "action": "create", + "new_state": { + "value": { + "securable_type": "model_provider_service", + "full_name": "", + "__embed__": [ + { + "principal": "deco-test-user@databricks.com", + "privileges": [ + "APPLY_TAG" + ] + } + ] + }, + "vars": { + "full_name": "${resources.model_provider_services.my_model_provider_service.id}" + } + } + } + } +} diff --git a/acceptance/bundle/resources/grants/model_provider_services/out.test.toml b/acceptance/bundle/resources/grants/model_provider_services/out.test.toml new file mode 100644 index 00000000000..59b56a2037c --- /dev/null +++ b/acceptance/bundle/resources/grants/model_provider_services/out.test.toml @@ -0,0 +1,3 @@ +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/resources/grants/model_provider_services/output.txt b/acceptance/bundle/resources/grants/model_provider_services/output.txt new file mode 100644 index 00000000000..350edf9f137 --- /dev/null +++ b/acceptance/bundle/resources/grants/model_provider_services/output.txt @@ -0,0 +1,35 @@ + +>>> [CLI] bundle plan -o json + +>>> print_requests.py --get //permissions + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-model-provider-service-grants-[UNIQUE_NAME]/default/files... +Created model_provider_services.my_model_provider_service +Created model_provider_services.my_model_provider_service.grants +Files: 7 uploaded, 0 deleted +Resources: 2 created, 0 changed, 0 deleted, 0 unchanged + +>>> print_requests.py //permissions + +>>> [CLI] grants get model_provider_service main.myschema.myservice +{ + "privilege_assignments": [ + { + "principal": "deco-test-user@databricks.com", + "privileges": [ + "APPLY_TAG" + ] + } + ] +} + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.model_provider_services.my_model_provider_service + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-model-provider-service-grants-[UNIQUE_NAME]/default + +Destroy: 1 deleted + +>>> print_requests.py //permissions diff --git a/acceptance/bundle/resources/grants/model_provider_services/script b/acceptance/bundle/resources/grants/model_provider_services/script new file mode 100644 index 00000000000..3cfa9e1c6cb --- /dev/null +++ b/acceptance/bundle/resources/grants/model_provider_services/script @@ -0,0 +1,12 @@ +envsubst < databricks.yml.tmpl > databricks.yml + +trace $CLI bundle plan -o json | jq 'del(.features)' > out.plan1.$DATABRICKS_BUNDLE_ENGINE.json +trace print_requests.py --get //permissions +trace $CLI bundle deploy +trace print_requests.py //permissions > out.deploy1.requests.$DATABRICKS_BUNDLE_ENGINE.json + +# Assert the end result: the grant is applied on the model provider service securable. +trace $CLI grants get model_provider_service main.myschema.myservice | jq --sort-keys + +trace $CLI bundle destroy --auto-approve +trace print_requests.py //permissions > out.destroy.requests.$DATABRICKS_BUNDLE_ENGINE.json diff --git a/acceptance/bundle/resources/grants/model_provider_services/test.toml b/acceptance/bundle/resources/grants/model_provider_services/test.toml new file mode 100644 index 00000000000..439e55ce050 --- /dev/null +++ b/acceptance/bundle/resources/grants/model_provider_services/test.toml @@ -0,0 +1,5 @@ +# AI Gateway securables are direct-engine only (no Terraform provider path), so +# there is no direct-vs-terraform request divergence to reconcile on cloud; +# compare the recorded requests locally instead. +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/acceptance/bundle/resources/grants/model_services/databricks.yml.tmpl b/acceptance/bundle/resources/grants/model_services/databricks.yml.tmpl new file mode 100644 index 00000000000..af6033b66dd --- /dev/null +++ b/acceptance/bundle/resources/grants/model_services/databricks.yml.tmpl @@ -0,0 +1,12 @@ +bundle: + name: deploy-model-service-grants-$UNIQUE_NAME + +resources: + model_services: + my_model_service: + parent: schemas/main.myschema + model_service_id: myservice + comment: mycomment + grants: + - principal: deco-test-user@databricks.com + privileges: ["APPLY_TAG"] diff --git a/acceptance/bundle/resources/grants/model_services/out.deploy1.requests.direct.json b/acceptance/bundle/resources/grants/model_services/out.deploy1.requests.direct.json new file mode 100644 index 00000000000..0cc3d553954 --- /dev/null +++ b/acceptance/bundle/resources/grants/model_services/out.deploy1.requests.direct.json @@ -0,0 +1,17 @@ +{ + "method": "PATCH", + "path": "/api/2.1/unity-catalog/permissions/model_service/main.myschema.myservice", + "body": { + "changes": [ + { + "add": [ + "APPLY_TAG" + ], + "principal": "deco-test-user@databricks.com", + "remove": [ + "ALL_PRIVILEGES" + ] + } + ] + } +} diff --git a/acceptance/bundle/resources/grants/model_services/out.destroy.requests.direct.json b/acceptance/bundle/resources/grants/model_services/out.destroy.requests.direct.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/acceptance/bundle/resources/grants/model_services/out.plan1.direct.json b/acceptance/bundle/resources/grants/model_services/out.plan1.direct.json new file mode 100644 index 00000000000..8fcd09fb0eb --- /dev/null +++ b/acceptance/bundle/resources/grants/model_services/out.plan1.direct.json @@ -0,0 +1,42 @@ +{ + "plan_version": [PLAN_VERSION], + "cli_version": "[CLI_VERSION]", + "plan": { + "resources.model_services.my_model_service": { + "action": "create", + "new_state": { + "value": { + "comment": "mycomment", + "model_service_id": "myservice", + "parent": "schemas/main.myschema" + } + } + }, + "resources.model_services.my_model_service.grants": { + "depends_on": [ + { + "node": "resources.model_services.my_model_service", + "label": "${resources.model_services.my_model_service.id}" + } + ], + "action": "create", + "new_state": { + "value": { + "securable_type": "model_service", + "full_name": "", + "__embed__": [ + { + "principal": "deco-test-user@databricks.com", + "privileges": [ + "APPLY_TAG" + ] + } + ] + }, + "vars": { + "full_name": "${resources.model_services.my_model_service.id}" + } + } + } + } +} diff --git a/acceptance/bundle/resources/grants/model_services/out.test.toml b/acceptance/bundle/resources/grants/model_services/out.test.toml new file mode 100644 index 00000000000..59b56a2037c --- /dev/null +++ b/acceptance/bundle/resources/grants/model_services/out.test.toml @@ -0,0 +1,3 @@ +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/resources/grants/model_services/output.txt b/acceptance/bundle/resources/grants/model_services/output.txt new file mode 100644 index 00000000000..e44df24529b --- /dev/null +++ b/acceptance/bundle/resources/grants/model_services/output.txt @@ -0,0 +1,35 @@ + +>>> [CLI] bundle plan -o json + +>>> print_requests.py --get //permissions + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-model-service-grants-[UNIQUE_NAME]/default/files... +Created model_services.my_model_service +Created model_services.my_model_service.grants +Files: 7 uploaded, 0 deleted +Resources: 2 created, 0 changed, 0 deleted, 0 unchanged + +>>> print_requests.py //permissions + +>>> [CLI] grants get model_service main.myschema.myservice +{ + "privilege_assignments": [ + { + "principal": "deco-test-user@databricks.com", + "privileges": [ + "APPLY_TAG" + ] + } + ] +} + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.model_services.my_model_service + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/deploy-model-service-grants-[UNIQUE_NAME]/default + +Destroy: 1 deleted + +>>> print_requests.py //permissions diff --git a/acceptance/bundle/resources/grants/model_services/script b/acceptance/bundle/resources/grants/model_services/script new file mode 100644 index 00000000000..01e2e1a56f1 --- /dev/null +++ b/acceptance/bundle/resources/grants/model_services/script @@ -0,0 +1,12 @@ +envsubst < databricks.yml.tmpl > databricks.yml + +trace $CLI bundle plan -o json | jq 'del(.features)' > out.plan1.$DATABRICKS_BUNDLE_ENGINE.json +trace print_requests.py --get //permissions +trace $CLI bundle deploy +trace print_requests.py //permissions > out.deploy1.requests.$DATABRICKS_BUNDLE_ENGINE.json + +# Assert the end result: the grant is applied on the model service securable. +trace $CLI grants get model_service main.myschema.myservice | jq --sort-keys + +trace $CLI bundle destroy --auto-approve +trace print_requests.py //permissions > out.destroy.requests.$DATABRICKS_BUNDLE_ENGINE.json diff --git a/acceptance/bundle/resources/grants/model_services/test.toml b/acceptance/bundle/resources/grants/model_services/test.toml new file mode 100644 index 00000000000..439e55ce050 --- /dev/null +++ b/acceptance/bundle/resources/grants/model_services/test.toml @@ -0,0 +1,5 @@ +# AI Gateway securables are direct-engine only (no Terraform provider path), so +# there is no direct-vs-terraform request divergence to reconcile on cloud; +# compare the recorded requests locally instead. +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["direct"] diff --git a/bundle/config/resources/mcp_service.go b/bundle/config/resources/mcp_service.go index db5f221b0d9..dd187f719bf 100644 --- a/bundle/config/resources/mcp_service.go +++ b/bundle/config/resources/mcp_service.go @@ -46,6 +46,12 @@ func (c McpServiceConfig) MarshalJSON() ([]byte, error) { type McpService struct { BaseResource McpServiceConfig + + // List of grants to apply on this MCP service. Grants are applied via the + // permissions API (the `.grants` sub-resource), not the MCP-service body, so + // this field lives on the wrapper and stays out of the diffed state that + // PrepareState returns (the embedded McpServiceConfig). + Grants []catalog.PrivilegeAssignment `json:"grants,omitempty"` } // UnmarshalJSON / MarshalJSON are defined on the wrapper so it does not inherit diff --git a/bundle/config/resources/model_provider_service.go b/bundle/config/resources/model_provider_service.go index 3339f2ae9a8..c97e2a5b98c 100644 --- a/bundle/config/resources/model_provider_service.go +++ b/bundle/config/resources/model_provider_service.go @@ -53,6 +53,12 @@ func (c ModelProviderServiceConfig) MarshalJSON() ([]byte, error) { type ModelProviderService struct { BaseResource ModelProviderServiceConfig + + // List of grants to apply on this model provider service. Grants are applied + // via the permissions API (the `.grants` sub-resource), not the service body, + // so this field lives on the wrapper and stays out of the diffed state that + // PrepareState returns (the embedded ModelProviderServiceConfig). + Grants []catalog.PrivilegeAssignment `json:"grants,omitempty"` } // UnmarshalJSON / MarshalJSON are defined on the wrapper so it does not inherit diff --git a/bundle/config/resources/model_service.go b/bundle/config/resources/model_service.go index 6f98ffbefb9..d83943dd090 100644 --- a/bundle/config/resources/model_service.go +++ b/bundle/config/resources/model_service.go @@ -53,6 +53,12 @@ func (c ModelServiceConfig) MarshalJSON() ([]byte, error) { type ModelService struct { BaseResource ModelServiceConfig + + // List of grants to apply on this model service. Grants are applied via the + // permissions API (the `.grants` sub-resource), not the model-service body, so + // this field lives on the wrapper and stays out of the diffed state that + // PrepareState returns (the embedded ModelServiceConfig). + Grants []catalog.PrivilegeAssignment `json:"grants,omitempty"` } // UnmarshalJSON / MarshalJSON are defined on the wrapper so it does not inherit diff --git a/bundle/direct/dresources/all.go b/bundle/direct/dresources/all.go index 942f7f1f648..27e8496b83e 100644 --- a/bundle/direct/dresources/all.go +++ b/bundle/direct/dresources/all.go @@ -66,13 +66,16 @@ var SupportedResources = map[string]any{ "instance_pools.permissions": (*ResourcePermissions)(nil), // Grants - "catalogs.grants": (*ResourceGrants)(nil), - "schemas.grants": (*ResourceGrants)(nil), - "external_locations.grants": (*ResourceGrants)(nil), - "volumes.grants": (*ResourceGrants)(nil), - "registered_models.grants": (*ResourceGrants)(nil), - "vector_search_indexes.grants": (*ResourceGrants)(nil), - "secrets.grants": (*ResourceGrants)(nil), + "catalogs.grants": (*ResourceGrants)(nil), + "schemas.grants": (*ResourceGrants)(nil), + "external_locations.grants": (*ResourceGrants)(nil), + "volumes.grants": (*ResourceGrants)(nil), + "registered_models.grants": (*ResourceGrants)(nil), + "vector_search_indexes.grants": (*ResourceGrants)(nil), + "secrets.grants": (*ResourceGrants)(nil), + "model_services.grants": (*ResourceGrants)(nil), + "mcp_services.grants": (*ResourceGrants)(nil), + "model_provider_services.grants": (*ResourceGrants)(nil), // Internal resources "internal_immutable_snapshots": (*ResourceSnapshot)(nil), diff --git a/bundle/direct/dresources/all_test.go b/bundle/direct/dresources/all_test.go index de607f04fa5..28170a4c02d 100644 --- a/bundle/direct/dresources/all_test.go +++ b/bundle/direct/dresources/all_test.go @@ -766,6 +766,39 @@ var testDeps = map[string]prepareWorkspace{ }, nil }, + "model_services.grants": func(ctx context.Context, client *databricks.WorkspaceClient) (any, error) { + return &GrantsState{ + SecurableType: "model_service", + FullName: "main.myschema.mymodelservice", + EmbeddedSlice: []catalog.PrivilegeAssignment{{ + Privileges: []catalog.Privilege{catalog.PrivilegeApplyTag}, + Principal: "user@example.com", + }}, + }, nil + }, + + "mcp_services.grants": func(ctx context.Context, client *databricks.WorkspaceClient) (any, error) { + return &GrantsState{ + SecurableType: "mcp_service", + FullName: "main.myschema.mymcpservice", + EmbeddedSlice: []catalog.PrivilegeAssignment{{ + Privileges: []catalog.Privilege{catalog.PrivilegeApplyTag}, + Principal: "user@example.com", + }}, + }, nil + }, + + "model_provider_services.grants": func(ctx context.Context, client *databricks.WorkspaceClient) (any, error) { + return &GrantsState{ + SecurableType: "model_provider_service", + FullName: "main.myschema.myproviderservice", + EmbeddedSlice: []catalog.PrivilegeAssignment{{ + Privileges: []catalog.Privilege{catalog.PrivilegeApplyTag}, + Principal: "user@example.com", + }}, + }, nil + }, + "secret_scopes.permissions": func(ctx context.Context, client *databricks.WorkspaceClient) (any, error) { err := client.Secrets.CreateScope(ctx, workspace.CreateScope{ Scope: "permissions_test_scope", diff --git a/bundle/direct/dresources/grants.go b/bundle/direct/dresources/grants.go index f9c31eeb75f..e9420bf3daa 100644 --- a/bundle/direct/dresources/grants.go +++ b/bundle/direct/dresources/grants.go @@ -13,13 +13,16 @@ import ( ) var grantResourceToSecurableType = map[string]string{ - "catalogs": "catalog", - "schemas": "schema", - "external_locations": "external_location", - "volumes": "volume", - "registered_models": "function", - "secrets": "secret", - "vector_search_indexes": "table", + "catalogs": "catalog", + "schemas": "schema", + "external_locations": "external_location", + "volumes": "volume", + "registered_models": "function", + "secrets": "secret", + "vector_search_indexes": "table", + "model_services": "model_service", + "mcp_services": "mcp_service", + "model_provider_services": "model_provider_service", } type GrantsState struct { diff --git a/bundle/internal/schema/annotations.yml b/bundle/internal/schema/annotations.yml index 07cbbe6467e..8623362e990 100644 --- a/bundle/internal/schema/annotations.yml +++ b/bundle/internal/schema/annotations.yml @@ -1204,6 +1204,15 @@ resources: "config": "description": |- PLACEHOLDER + "$fields": + "source_connection": + "$fields": + "is_deleted": + "description": |- + PLACEHOLDER + "grants": + "description": |- + PLACEHOLDER "lifecycle": "description": |- PLACEHOLDER @@ -1223,6 +1232,9 @@ resources: "config": "description": |- PLACEHOLDER + "grants": + "description": |- + PLACEHOLDER "lifecycle": "description": |- PLACEHOLDER @@ -1242,6 +1254,9 @@ resources: "config": "description": |- PLACEHOLDER + "grants": + "description": |- + PLACEHOLDER "lifecycle": "description": |- PLACEHOLDER diff --git a/bundle/internal/validation/generated/enum_fields.go b/bundle/internal/validation/generated/enum_fields.go index 464afe2f97d..cfa346ebd0a 100644 --- a/bundle/internal/validation/generated/enum_fields.go +++ b/bundle/internal/validation/generated/enum_fields.go @@ -160,15 +160,18 @@ var EnumFields = map[string][]string{ "resources.mcp_services.*.config.rate_limits[*].key": {"RATE_LIMIT_KEY_SERVICE", "RATE_LIMIT_KEY_SERVICE_PRINCIPAL", "RATE_LIMIT_KEY_USER", "RATE_LIMIT_KEY_USER_DEFAULT", "RATE_LIMIT_KEY_USER_GROUP"}, "resources.mcp_services.*.config.rate_limits[*].renewal_period": {"RATE_LIMIT_RENEWAL_PERIOD_HOUR", "RATE_LIMIT_RENEWAL_PERIOD_MINUTE"}, + "resources.mcp_services.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_METADATA", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, "resources.model_provider_services.*.config.provider_type": {"EXTERNAL_MODEL_PROVIDER_TYPE_AMAZON_BEDROCK", "EXTERNAL_MODEL_PROVIDER_TYPE_ANTHROPIC", "EXTERNAL_MODEL_PROVIDER_TYPE_AZURE_OPENAI", "EXTERNAL_MODEL_PROVIDER_TYPE_CUSTOM", "EXTERNAL_MODEL_PROVIDER_TYPE_GEMINI_ENTERPRISE", "EXTERNAL_MODEL_PROVIDER_TYPE_MICROSOFT_FOUNDRY", "EXTERNAL_MODEL_PROVIDER_TYPE_OPENAI"}, "resources.model_provider_services.*.config.rate_limits[*].key": {"RATE_LIMIT_KEY_SERVICE", "RATE_LIMIT_KEY_SERVICE_PRINCIPAL", "RATE_LIMIT_KEY_USER", "RATE_LIMIT_KEY_USER_DEFAULT", "RATE_LIMIT_KEY_USER_GROUP"}, "resources.model_provider_services.*.config.rate_limits[*].renewal_period": {"RATE_LIMIT_RENEWAL_PERIOD_HOUR", "RATE_LIMIT_RENEWAL_PERIOD_MINUTE"}, + "resources.model_provider_services.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_METADATA", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, "resources.model_services.*.config.rate_limits[*].key": {"RATE_LIMIT_KEY_SERVICE", "RATE_LIMIT_KEY_SERVICE_PRINCIPAL", "RATE_LIMIT_KEY_USER", "RATE_LIMIT_KEY_USER_DEFAULT", "RATE_LIMIT_KEY_USER_GROUP"}, "resources.model_services.*.config.rate_limits[*].renewal_period": {"RATE_LIMIT_RENEWAL_PERIOD_HOUR", "RATE_LIMIT_RENEWAL_PERIOD_MINUTE"}, "resources.model_services.*.config.routing.destinations[*].destination_type": {"DESTINATION_TYPE_EXTERNAL_FOUNDATION_MODEL", "DESTINATION_TYPE_PAY_PER_TOKEN_FOUNDATION_MODEL", "DESTINATION_TYPE_PROVISIONED_THROUGHPUT_FOUNDATION_MODEL"}, "resources.model_services.*.config.routing.fallback.destinations[*].destination_type": {"DESTINATION_TYPE_EXTERNAL_FOUNDATION_MODEL", "DESTINATION_TYPE_PAY_PER_TOKEN_FOUNDATION_MODEL", "DESTINATION_TYPE_PROVISIONED_THROUGHPUT_FOUNDATION_MODEL"}, + "resources.model_services.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_METADATA", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, "resources.model_serving_endpoints.*.ai_gateway.guardrails.input.pii.behavior": {"BLOCK", "MASK", "NONE"}, "resources.model_serving_endpoints.*.ai_gateway.guardrails.output.pii.behavior": {"BLOCK", "MASK", "NONE"}, diff --git a/bundle/schema/jsonschema.json b/bundle/schema/jsonschema.json index fc398289193..cfa257d0ed8 100644 --- a/bundle/schema/jsonschema.json +++ b/bundle/schema/jsonschema.json @@ -1600,6 +1600,9 @@ "config": { "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/catalog.McpServiceConfig" }, + "grants": { + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" + }, "lifecycle": { "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle" }, @@ -1789,6 +1792,9 @@ "config": { "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/catalog.ModelProviderServiceConfig" }, + "grants": { + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" + }, "lifecycle": { "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle" }, @@ -1822,6 +1828,9 @@ "config": { "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/catalog.ModelServiceConfig" }, + "grants": { + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" + }, "lifecycle": { "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle" }, diff --git a/python/databricks/bundles/mcp_services/__init__.py b/python/databricks/bundles/mcp_services/__init__.py index b1aed03e279..a4fe01b5199 100644 --- a/python/databricks/bundles/mcp_services/__init__.py +++ b/python/databricks/bundles/mcp_services/__init__.py @@ -13,6 +13,11 @@ "McpServiceConfigSourceConnectionParam", "McpServiceDict", "McpServiceParam", + "Privilege", + "PrivilegeAssignment", + "PrivilegeAssignmentDict", + "PrivilegeAssignmentParam", + "PrivilegeParam", "RateLimit", "RateLimitDict", "RateLimitParam", @@ -43,6 +48,12 @@ McpServiceConfigSourceConnectionDict, McpServiceConfigSourceConnectionParam, ) +from databricks.bundles.mcp_services._models.privilege import Privilege, PrivilegeParam +from databricks.bundles.mcp_services._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentDict, + PrivilegeAssignmentParam, +) from databricks.bundles.mcp_services._models.rate_limit import ( RateLimit, RateLimitDict, diff --git a/python/databricks/bundles/mcp_services/_models/mcp_service.py b/python/databricks/bundles/mcp_services/_models/mcp_service.py index 7dde9d68a7f..1050e5153f4 100644 --- a/python/databricks/bundles/mcp_services/_models/mcp_service.py +++ b/python/databricks/bundles/mcp_services/_models/mcp_service.py @@ -1,17 +1,28 @@ # Code generated by pydabs-codegen. DO NOT EDIT. -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict from databricks.bundles.core._resource import Resource from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value -from databricks.bundles.core._variable import VariableOr, VariableOrOptional -from databricks.bundles.mcp_services._models.lifecycle import Lifecycle, LifecycleParam +from databricks.bundles.core._variable import ( + VariableOr, + VariableOrList, + VariableOrOptional, +) +from databricks.bundles.mcp_services._models.lifecycle import ( + Lifecycle, + LifecycleParam, +) from databricks.bundles.mcp_services._models.mcp_service_config import ( McpServiceConfig, McpServiceConfigParam, ) +from databricks.bundles.mcp_services._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentParam, +) if TYPE_CHECKING: from typing_extensions import Self @@ -29,6 +40,8 @@ class McpService(Resource): config: VariableOrOptional[McpServiceConfig] = None + grants: VariableOrList[PrivilegeAssignment] = field(default_factory=list) + lifecycle: VariableOrOptional[Lifecycle] = None @classmethod @@ -50,6 +63,8 @@ class McpServiceDict(TypedDict, total=False): config: VariableOrOptional[McpServiceConfigParam] + grants: VariableOrList[PrivilegeAssignmentParam] + lifecycle: VariableOrOptional[LifecycleParam] diff --git a/python/databricks/bundles/mcp_services/_models/mcp_service_config.py b/python/databricks/bundles/mcp_services/_models/mcp_service_config.py index 155550ba925..5a9a984bf01 100644 --- a/python/databricks/bundles/mcp_services/_models/mcp_service_config.py +++ b/python/databricks/bundles/mcp_services/_models/mcp_service_config.py @@ -10,7 +10,10 @@ McpServiceConfigSourceConnection, McpServiceConfigSourceConnectionParam, ) -from databricks.bundles.mcp_services._models.rate_limit import RateLimit, RateLimitParam +from databricks.bundles.mcp_services._models.rate_limit import ( + RateLimit, + RateLimitParam, +) if TYPE_CHECKING: from typing_extensions import Self diff --git a/python/databricks/bundles/mcp_services/_models/privilege.py b/python/databricks/bundles/mcp_services/_models/privilege.py new file mode 100644 index 00000000000..21a52a2f112 --- /dev/null +++ b/python/databricks/bundles/mcp_services/_models/privilege.py @@ -0,0 +1,116 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from enum import Enum +from typing import Literal + + +class Privilege(Enum): + SELECT = "SELECT" + READ_PRIVATE_FILES = "READ_PRIVATE_FILES" + WRITE_PRIVATE_FILES = "WRITE_PRIVATE_FILES" + CREATE = "CREATE" + USAGE = "USAGE" + USE_CATALOG = "USE_CATALOG" + USE_SCHEMA = "USE_SCHEMA" + CREATE_SCHEMA = "CREATE_SCHEMA" + CREATE_VIEW = "CREATE_VIEW" + CREATE_EXTERNAL_TABLE = "CREATE_EXTERNAL_TABLE" + CREATE_MATERIALIZED_VIEW = "CREATE_MATERIALIZED_VIEW" + CREATE_FUNCTION = "CREATE_FUNCTION" + CREATE_MODEL = "CREATE_MODEL" + CREATE_CATALOG = "CREATE_CATALOG" + CREATE_MANAGED_STORAGE = "CREATE_MANAGED_STORAGE" + CREATE_EXTERNAL_LOCATION = "CREATE_EXTERNAL_LOCATION" + CREATE_STORAGE_CREDENTIAL = "CREATE_STORAGE_CREDENTIAL" + CREATE_SERVICE_CREDENTIAL = "CREATE_SERVICE_CREDENTIAL" + ACCESS = "ACCESS" + CREATE_SHARE = "CREATE_SHARE" + CREATE_RECIPIENT = "CREATE_RECIPIENT" + CREATE_PROVIDER = "CREATE_PROVIDER" + USE_SHARE = "USE_SHARE" + USE_RECIPIENT = "USE_RECIPIENT" + USE_PROVIDER = "USE_PROVIDER" + USE_MARKETPLACE_ASSETS = "USE_MARKETPLACE_ASSETS" + SET_SHARE_PERMISSION = "SET_SHARE_PERMISSION" + MODIFY = "MODIFY" + REFRESH = "REFRESH" + EXECUTE = "EXECUTE" + READ_FILES = "READ_FILES" + WRITE_FILES = "WRITE_FILES" + CREATE_TABLE = "CREATE_TABLE" + ALL_PRIVILEGES = "ALL_PRIVILEGES" + CREATE_CONNECTION = "CREATE_CONNECTION" + USE_CONNECTION = "USE_CONNECTION" + APPLY_TAG = "APPLY_TAG" + CREATE_FOREIGN_CATALOG = "CREATE_FOREIGN_CATALOG" + CREATE_FOREIGN_SECURABLE = "CREATE_FOREIGN_SECURABLE" + MANAGE_ALLOWLIST = "MANAGE_ALLOWLIST" + CREATE_VOLUME = "CREATE_VOLUME" + CREATE_EXTERNAL_VOLUME = "CREATE_EXTERNAL_VOLUME" + READ_VOLUME = "READ_VOLUME" + WRITE_VOLUME = "WRITE_VOLUME" + MANAGE = "MANAGE" + BROWSE = "BROWSE" + CREATE_CLEAN_ROOM = "CREATE_CLEAN_ROOM" + MODIFY_CLEAN_ROOM = "MODIFY_CLEAN_ROOM" + EXECUTE_CLEAN_ROOM_TASK = "EXECUTE_CLEAN_ROOM_TASK" + EXTERNAL_USE_SCHEMA = "EXTERNAL_USE_SCHEMA" + READ_METADATA = "READ_METADATA" + + +PrivilegeParam = ( + Literal[ + "SELECT", + "READ_PRIVATE_FILES", + "WRITE_PRIVATE_FILES", + "CREATE", + "USAGE", + "USE_CATALOG", + "USE_SCHEMA", + "CREATE_SCHEMA", + "CREATE_VIEW", + "CREATE_EXTERNAL_TABLE", + "CREATE_MATERIALIZED_VIEW", + "CREATE_FUNCTION", + "CREATE_MODEL", + "CREATE_CATALOG", + "CREATE_MANAGED_STORAGE", + "CREATE_EXTERNAL_LOCATION", + "CREATE_STORAGE_CREDENTIAL", + "CREATE_SERVICE_CREDENTIAL", + "ACCESS", + "CREATE_SHARE", + "CREATE_RECIPIENT", + "CREATE_PROVIDER", + "USE_SHARE", + "USE_RECIPIENT", + "USE_PROVIDER", + "USE_MARKETPLACE_ASSETS", + "SET_SHARE_PERMISSION", + "MODIFY", + "REFRESH", + "EXECUTE", + "READ_FILES", + "WRITE_FILES", + "CREATE_TABLE", + "ALL_PRIVILEGES", + "CREATE_CONNECTION", + "USE_CONNECTION", + "APPLY_TAG", + "CREATE_FOREIGN_CATALOG", + "CREATE_FOREIGN_SECURABLE", + "MANAGE_ALLOWLIST", + "CREATE_VOLUME", + "CREATE_EXTERNAL_VOLUME", + "READ_VOLUME", + "WRITE_VOLUME", + "MANAGE", + "BROWSE", + "CREATE_CLEAN_ROOM", + "MODIFY_CLEAN_ROOM", + "EXECUTE_CLEAN_ROOM_TASK", + "EXTERNAL_USE_SCHEMA", + "READ_METADATA", + ] + | Privilege +) diff --git a/python/databricks/bundles/mcp_services/_models/privilege_assignment.py b/python/databricks/bundles/mcp_services/_models/privilege_assignment.py new file mode 100644 index 00000000000..cdaba80f76a --- /dev/null +++ b/python/databricks/bundles/mcp_services/_models/privilege_assignment.py @@ -0,0 +1,53 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.mcp_services._models.privilege import Privilege, PrivilegeParam + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class PrivilegeAssignment: + """""" + + principal: VariableOrOptional[str] = None + """ + The principal (user email address or group name). + For deleted principals, `principal` is empty while `principal_id` is populated. + """ + + privileges: VariableOrList[Privilege] = field(default_factory=list) + """ + The privileges assigned to the principal. + """ + + @classmethod + def from_dict(cls, value: "PrivilegeAssignmentDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "PrivilegeAssignmentDict": + return _transform_to_json_value(self) # type:ignore + + +class PrivilegeAssignmentDict(TypedDict, total=False): + """""" + + principal: VariableOrOptional[str] + """ + The principal (user email address or group name). + For deleted principals, `principal` is empty while `principal_id` is populated. + """ + + privileges: VariableOrList[PrivilegeParam] + """ + The privileges assigned to the principal. + """ + + +PrivilegeAssignmentParam = PrivilegeAssignmentDict | PrivilegeAssignment diff --git a/python/databricks/bundles/model_provider_services/__init__.py b/python/databricks/bundles/model_provider_services/__init__.py index 17a2fb82470..d256f195862 100644 --- a/python/databricks/bundles/model_provider_services/__init__.py +++ b/python/databricks/bundles/model_provider_services/__init__.py @@ -75,6 +75,11 @@ "ModelProviderServiceConfigServiceCredentialParam", "ModelProviderServiceDict", "ModelProviderServiceParam", + "Privilege", + "PrivilegeAssignment", + "PrivilegeAssignmentDict", + "PrivilegeAssignmentParam", + "PrivilegeParam", "RateLimit", "RateLimitDict", "RateLimitParam", @@ -209,6 +214,15 @@ ModelProviderServiceConfigServiceCredentialDict, ModelProviderServiceConfigServiceCredentialParam, ) +from databricks.bundles.model_provider_services._models.privilege import ( + Privilege, + PrivilegeParam, +) +from databricks.bundles.model_provider_services._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentDict, + PrivilegeAssignmentParam, +) from databricks.bundles.model_provider_services._models.rate_limit import ( RateLimit, RateLimitDict, diff --git a/python/databricks/bundles/model_provider_services/_models/model_provider_service.py b/python/databricks/bundles/model_provider_services/_models/model_provider_service.py index 65fcb48e421..41a21652ac8 100644 --- a/python/databricks/bundles/model_provider_services/_models/model_provider_service.py +++ b/python/databricks/bundles/model_provider_services/_models/model_provider_service.py @@ -1,12 +1,16 @@ # Code generated by pydabs-codegen. DO NOT EDIT. -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict from databricks.bundles.core._resource import Resource from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value -from databricks.bundles.core._variable import VariableOr, VariableOrOptional +from databricks.bundles.core._variable import ( + VariableOr, + VariableOrList, + VariableOrOptional, +) from databricks.bundles.model_provider_services._models.lifecycle import ( Lifecycle, LifecycleParam, @@ -15,6 +19,10 @@ ModelProviderServiceConfig, ModelProviderServiceConfigParam, ) +from databricks.bundles.model_provider_services._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentParam, +) if TYPE_CHECKING: from typing_extensions import Self @@ -32,6 +40,8 @@ class ModelProviderService(Resource): config: VariableOrOptional[ModelProviderServiceConfig] = None + grants: VariableOrList[PrivilegeAssignment] = field(default_factory=list) + lifecycle: VariableOrOptional[Lifecycle] = None @classmethod @@ -53,6 +63,8 @@ class ModelProviderServiceDict(TypedDict, total=False): config: VariableOrOptional[ModelProviderServiceConfigParam] + grants: VariableOrList[PrivilegeAssignmentParam] + lifecycle: VariableOrOptional[LifecycleParam] diff --git a/python/databricks/bundles/model_provider_services/_models/privilege.py b/python/databricks/bundles/model_provider_services/_models/privilege.py new file mode 100644 index 00000000000..21a52a2f112 --- /dev/null +++ b/python/databricks/bundles/model_provider_services/_models/privilege.py @@ -0,0 +1,116 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from enum import Enum +from typing import Literal + + +class Privilege(Enum): + SELECT = "SELECT" + READ_PRIVATE_FILES = "READ_PRIVATE_FILES" + WRITE_PRIVATE_FILES = "WRITE_PRIVATE_FILES" + CREATE = "CREATE" + USAGE = "USAGE" + USE_CATALOG = "USE_CATALOG" + USE_SCHEMA = "USE_SCHEMA" + CREATE_SCHEMA = "CREATE_SCHEMA" + CREATE_VIEW = "CREATE_VIEW" + CREATE_EXTERNAL_TABLE = "CREATE_EXTERNAL_TABLE" + CREATE_MATERIALIZED_VIEW = "CREATE_MATERIALIZED_VIEW" + CREATE_FUNCTION = "CREATE_FUNCTION" + CREATE_MODEL = "CREATE_MODEL" + CREATE_CATALOG = "CREATE_CATALOG" + CREATE_MANAGED_STORAGE = "CREATE_MANAGED_STORAGE" + CREATE_EXTERNAL_LOCATION = "CREATE_EXTERNAL_LOCATION" + CREATE_STORAGE_CREDENTIAL = "CREATE_STORAGE_CREDENTIAL" + CREATE_SERVICE_CREDENTIAL = "CREATE_SERVICE_CREDENTIAL" + ACCESS = "ACCESS" + CREATE_SHARE = "CREATE_SHARE" + CREATE_RECIPIENT = "CREATE_RECIPIENT" + CREATE_PROVIDER = "CREATE_PROVIDER" + USE_SHARE = "USE_SHARE" + USE_RECIPIENT = "USE_RECIPIENT" + USE_PROVIDER = "USE_PROVIDER" + USE_MARKETPLACE_ASSETS = "USE_MARKETPLACE_ASSETS" + SET_SHARE_PERMISSION = "SET_SHARE_PERMISSION" + MODIFY = "MODIFY" + REFRESH = "REFRESH" + EXECUTE = "EXECUTE" + READ_FILES = "READ_FILES" + WRITE_FILES = "WRITE_FILES" + CREATE_TABLE = "CREATE_TABLE" + ALL_PRIVILEGES = "ALL_PRIVILEGES" + CREATE_CONNECTION = "CREATE_CONNECTION" + USE_CONNECTION = "USE_CONNECTION" + APPLY_TAG = "APPLY_TAG" + CREATE_FOREIGN_CATALOG = "CREATE_FOREIGN_CATALOG" + CREATE_FOREIGN_SECURABLE = "CREATE_FOREIGN_SECURABLE" + MANAGE_ALLOWLIST = "MANAGE_ALLOWLIST" + CREATE_VOLUME = "CREATE_VOLUME" + CREATE_EXTERNAL_VOLUME = "CREATE_EXTERNAL_VOLUME" + READ_VOLUME = "READ_VOLUME" + WRITE_VOLUME = "WRITE_VOLUME" + MANAGE = "MANAGE" + BROWSE = "BROWSE" + CREATE_CLEAN_ROOM = "CREATE_CLEAN_ROOM" + MODIFY_CLEAN_ROOM = "MODIFY_CLEAN_ROOM" + EXECUTE_CLEAN_ROOM_TASK = "EXECUTE_CLEAN_ROOM_TASK" + EXTERNAL_USE_SCHEMA = "EXTERNAL_USE_SCHEMA" + READ_METADATA = "READ_METADATA" + + +PrivilegeParam = ( + Literal[ + "SELECT", + "READ_PRIVATE_FILES", + "WRITE_PRIVATE_FILES", + "CREATE", + "USAGE", + "USE_CATALOG", + "USE_SCHEMA", + "CREATE_SCHEMA", + "CREATE_VIEW", + "CREATE_EXTERNAL_TABLE", + "CREATE_MATERIALIZED_VIEW", + "CREATE_FUNCTION", + "CREATE_MODEL", + "CREATE_CATALOG", + "CREATE_MANAGED_STORAGE", + "CREATE_EXTERNAL_LOCATION", + "CREATE_STORAGE_CREDENTIAL", + "CREATE_SERVICE_CREDENTIAL", + "ACCESS", + "CREATE_SHARE", + "CREATE_RECIPIENT", + "CREATE_PROVIDER", + "USE_SHARE", + "USE_RECIPIENT", + "USE_PROVIDER", + "USE_MARKETPLACE_ASSETS", + "SET_SHARE_PERMISSION", + "MODIFY", + "REFRESH", + "EXECUTE", + "READ_FILES", + "WRITE_FILES", + "CREATE_TABLE", + "ALL_PRIVILEGES", + "CREATE_CONNECTION", + "USE_CONNECTION", + "APPLY_TAG", + "CREATE_FOREIGN_CATALOG", + "CREATE_FOREIGN_SECURABLE", + "MANAGE_ALLOWLIST", + "CREATE_VOLUME", + "CREATE_EXTERNAL_VOLUME", + "READ_VOLUME", + "WRITE_VOLUME", + "MANAGE", + "BROWSE", + "CREATE_CLEAN_ROOM", + "MODIFY_CLEAN_ROOM", + "EXECUTE_CLEAN_ROOM_TASK", + "EXTERNAL_USE_SCHEMA", + "READ_METADATA", + ] + | Privilege +) diff --git a/python/databricks/bundles/model_provider_services/_models/privilege_assignment.py b/python/databricks/bundles/model_provider_services/_models/privilege_assignment.py new file mode 100644 index 00000000000..810d4ebb627 --- /dev/null +++ b/python/databricks/bundles/model_provider_services/_models/privilege_assignment.py @@ -0,0 +1,56 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.model_provider_services._models.privilege import ( + Privilege, + PrivilegeParam, +) + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class PrivilegeAssignment: + """""" + + principal: VariableOrOptional[str] = None + """ + The principal (user email address or group name). + For deleted principals, `principal` is empty while `principal_id` is populated. + """ + + privileges: VariableOrList[Privilege] = field(default_factory=list) + """ + The privileges assigned to the principal. + """ + + @classmethod + def from_dict(cls, value: "PrivilegeAssignmentDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "PrivilegeAssignmentDict": + return _transform_to_json_value(self) # type:ignore + + +class PrivilegeAssignmentDict(TypedDict, total=False): + """""" + + principal: VariableOrOptional[str] + """ + The principal (user email address or group name). + For deleted principals, `principal` is empty while `principal_id` is populated. + """ + + privileges: VariableOrList[PrivilegeParam] + """ + The privileges assigned to the principal. + """ + + +PrivilegeAssignmentParam = PrivilegeAssignmentDict | PrivilegeAssignment diff --git a/python/databricks/bundles/model_services/__init__.py b/python/databricks/bundles/model_services/__init__.py index 3ab1e5510ad..b2e2f75719a 100644 --- a/python/databricks/bundles/model_services/__init__.py +++ b/python/databricks/bundles/model_services/__init__.py @@ -34,8 +34,16 @@ "ModelServiceConfigRoutingConfig", "ModelServiceConfigRoutingConfigDict", "ModelServiceConfigRoutingConfigParam", + "ModelServiceConfigRoutingConfigTrafficSplitting", + "ModelServiceConfigRoutingConfigTrafficSplittingDict", + "ModelServiceConfigRoutingConfigTrafficSplittingParam", "ModelServiceDict", "ModelServiceParam", + "Privilege", + "PrivilegeAssignment", + "PrivilegeAssignmentDict", + "PrivilegeAssignmentParam", + "PrivilegeParam", "RateLimit", "RateLimitDict", "RateLimitParam", @@ -105,6 +113,20 @@ ModelServiceConfigRoutingConfigDict, ModelServiceConfigRoutingConfigParam, ) +from databricks.bundles.model_services._models.model_service_config_routing_config_traffic_splitting import ( + ModelServiceConfigRoutingConfigTrafficSplitting, + ModelServiceConfigRoutingConfigTrafficSplittingDict, + ModelServiceConfigRoutingConfigTrafficSplittingParam, +) +from databricks.bundles.model_services._models.privilege import ( + Privilege, + PrivilegeParam, +) +from databricks.bundles.model_services._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentDict, + PrivilegeAssignmentParam, +) from databricks.bundles.model_services._models.rate_limit import ( RateLimit, RateLimitDict, diff --git a/python/databricks/bundles/model_services/_models/model_service.py b/python/databricks/bundles/model_services/_models/model_service.py index d5eab192811..88f9d8cdeb7 100644 --- a/python/databricks/bundles/model_services/_models/model_service.py +++ b/python/databricks/bundles/model_services/_models/model_service.py @@ -1,12 +1,16 @@ # Code generated by pydabs-codegen. DO NOT EDIT. -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict from databricks.bundles.core._resource import Resource from databricks.bundles.core._transform import _transform from databricks.bundles.core._transform_to_json import _transform_to_json_value -from databricks.bundles.core._variable import VariableOr, VariableOrOptional +from databricks.bundles.core._variable import ( + VariableOr, + VariableOrList, + VariableOrOptional, +) from databricks.bundles.model_services._models.lifecycle import ( Lifecycle, LifecycleParam, @@ -15,6 +19,10 @@ ModelServiceConfig, ModelServiceConfigParam, ) +from databricks.bundles.model_services._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentParam, +) if TYPE_CHECKING: from typing_extensions import Self @@ -32,6 +40,8 @@ class ModelService(Resource): config: VariableOrOptional[ModelServiceConfig] = None + grants: VariableOrList[PrivilegeAssignment] = field(default_factory=list) + lifecycle: VariableOrOptional[Lifecycle] = None @classmethod @@ -53,6 +63,8 @@ class ModelServiceDict(TypedDict, total=False): config: VariableOrOptional[ModelServiceConfigParam] + grants: VariableOrList[PrivilegeAssignmentParam] + lifecycle: VariableOrOptional[LifecycleParam] diff --git a/python/databricks/bundles/model_services/_models/privilege.py b/python/databricks/bundles/model_services/_models/privilege.py new file mode 100644 index 00000000000..21a52a2f112 --- /dev/null +++ b/python/databricks/bundles/model_services/_models/privilege.py @@ -0,0 +1,116 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from enum import Enum +from typing import Literal + + +class Privilege(Enum): + SELECT = "SELECT" + READ_PRIVATE_FILES = "READ_PRIVATE_FILES" + WRITE_PRIVATE_FILES = "WRITE_PRIVATE_FILES" + CREATE = "CREATE" + USAGE = "USAGE" + USE_CATALOG = "USE_CATALOG" + USE_SCHEMA = "USE_SCHEMA" + CREATE_SCHEMA = "CREATE_SCHEMA" + CREATE_VIEW = "CREATE_VIEW" + CREATE_EXTERNAL_TABLE = "CREATE_EXTERNAL_TABLE" + CREATE_MATERIALIZED_VIEW = "CREATE_MATERIALIZED_VIEW" + CREATE_FUNCTION = "CREATE_FUNCTION" + CREATE_MODEL = "CREATE_MODEL" + CREATE_CATALOG = "CREATE_CATALOG" + CREATE_MANAGED_STORAGE = "CREATE_MANAGED_STORAGE" + CREATE_EXTERNAL_LOCATION = "CREATE_EXTERNAL_LOCATION" + CREATE_STORAGE_CREDENTIAL = "CREATE_STORAGE_CREDENTIAL" + CREATE_SERVICE_CREDENTIAL = "CREATE_SERVICE_CREDENTIAL" + ACCESS = "ACCESS" + CREATE_SHARE = "CREATE_SHARE" + CREATE_RECIPIENT = "CREATE_RECIPIENT" + CREATE_PROVIDER = "CREATE_PROVIDER" + USE_SHARE = "USE_SHARE" + USE_RECIPIENT = "USE_RECIPIENT" + USE_PROVIDER = "USE_PROVIDER" + USE_MARKETPLACE_ASSETS = "USE_MARKETPLACE_ASSETS" + SET_SHARE_PERMISSION = "SET_SHARE_PERMISSION" + MODIFY = "MODIFY" + REFRESH = "REFRESH" + EXECUTE = "EXECUTE" + READ_FILES = "READ_FILES" + WRITE_FILES = "WRITE_FILES" + CREATE_TABLE = "CREATE_TABLE" + ALL_PRIVILEGES = "ALL_PRIVILEGES" + CREATE_CONNECTION = "CREATE_CONNECTION" + USE_CONNECTION = "USE_CONNECTION" + APPLY_TAG = "APPLY_TAG" + CREATE_FOREIGN_CATALOG = "CREATE_FOREIGN_CATALOG" + CREATE_FOREIGN_SECURABLE = "CREATE_FOREIGN_SECURABLE" + MANAGE_ALLOWLIST = "MANAGE_ALLOWLIST" + CREATE_VOLUME = "CREATE_VOLUME" + CREATE_EXTERNAL_VOLUME = "CREATE_EXTERNAL_VOLUME" + READ_VOLUME = "READ_VOLUME" + WRITE_VOLUME = "WRITE_VOLUME" + MANAGE = "MANAGE" + BROWSE = "BROWSE" + CREATE_CLEAN_ROOM = "CREATE_CLEAN_ROOM" + MODIFY_CLEAN_ROOM = "MODIFY_CLEAN_ROOM" + EXECUTE_CLEAN_ROOM_TASK = "EXECUTE_CLEAN_ROOM_TASK" + EXTERNAL_USE_SCHEMA = "EXTERNAL_USE_SCHEMA" + READ_METADATA = "READ_METADATA" + + +PrivilegeParam = ( + Literal[ + "SELECT", + "READ_PRIVATE_FILES", + "WRITE_PRIVATE_FILES", + "CREATE", + "USAGE", + "USE_CATALOG", + "USE_SCHEMA", + "CREATE_SCHEMA", + "CREATE_VIEW", + "CREATE_EXTERNAL_TABLE", + "CREATE_MATERIALIZED_VIEW", + "CREATE_FUNCTION", + "CREATE_MODEL", + "CREATE_CATALOG", + "CREATE_MANAGED_STORAGE", + "CREATE_EXTERNAL_LOCATION", + "CREATE_STORAGE_CREDENTIAL", + "CREATE_SERVICE_CREDENTIAL", + "ACCESS", + "CREATE_SHARE", + "CREATE_RECIPIENT", + "CREATE_PROVIDER", + "USE_SHARE", + "USE_RECIPIENT", + "USE_PROVIDER", + "USE_MARKETPLACE_ASSETS", + "SET_SHARE_PERMISSION", + "MODIFY", + "REFRESH", + "EXECUTE", + "READ_FILES", + "WRITE_FILES", + "CREATE_TABLE", + "ALL_PRIVILEGES", + "CREATE_CONNECTION", + "USE_CONNECTION", + "APPLY_TAG", + "CREATE_FOREIGN_CATALOG", + "CREATE_FOREIGN_SECURABLE", + "MANAGE_ALLOWLIST", + "CREATE_VOLUME", + "CREATE_EXTERNAL_VOLUME", + "READ_VOLUME", + "WRITE_VOLUME", + "MANAGE", + "BROWSE", + "CREATE_CLEAN_ROOM", + "MODIFY_CLEAN_ROOM", + "EXECUTE_CLEAN_ROOM_TASK", + "EXTERNAL_USE_SCHEMA", + "READ_METADATA", + ] + | Privilege +) diff --git a/python/databricks/bundles/model_services/_models/privilege_assignment.py b/python/databricks/bundles/model_services/_models/privilege_assignment.py new file mode 100644 index 00000000000..7bbd0ac80ee --- /dev/null +++ b/python/databricks/bundles/model_services/_models/privilege_assignment.py @@ -0,0 +1,56 @@ +# Code generated by pydabs-codegen. DO NOT EDIT. + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.core._transform import _transform +from databricks.bundles.core._transform_to_json import _transform_to_json_value +from databricks.bundles.core._variable import VariableOrList, VariableOrOptional +from databricks.bundles.model_services._models.privilege import ( + Privilege, + PrivilegeParam, +) + +if TYPE_CHECKING: + from typing_extensions import Self + + +@dataclass(kw_only=True) +class PrivilegeAssignment: + """""" + + principal: VariableOrOptional[str] = None + """ + The principal (user email address or group name). + For deleted principals, `principal` is empty while `principal_id` is populated. + """ + + privileges: VariableOrList[Privilege] = field(default_factory=list) + """ + The privileges assigned to the principal. + """ + + @classmethod + def from_dict(cls, value: "PrivilegeAssignmentDict") -> "Self": + return _transform(cls, value) + + def as_dict(self) -> "PrivilegeAssignmentDict": + return _transform_to_json_value(self) # type:ignore + + +class PrivilegeAssignmentDict(TypedDict, total=False): + """""" + + principal: VariableOrOptional[str] + """ + The principal (user email address or group name). + For deleted principals, `principal` is empty while `principal_id` is populated. + """ + + privileges: VariableOrList[PrivilegeParam] + """ + The privileges assigned to the principal. + """ + + +PrivilegeAssignmentParam = PrivilegeAssignmentDict | PrivilegeAssignment diff --git a/python/databricks_tests/core/_generated/mcp_services.py b/python/databricks_tests/core/_generated/mcp_services.py index 7865a4b5ec1..ca1247a300d 100644 --- a/python/databricks_tests/core/_generated/mcp_services.py +++ b/python/databricks_tests/core/_generated/mcp_services.py @@ -5,6 +5,9 @@ from databricks.bundles.mcp_services._models.lifecycle import Lifecycle from databricks.bundles.mcp_services._models.mcp_service import McpService from databricks.bundles.mcp_services._models.mcp_service_config import McpServiceConfig +from databricks.bundles.mcp_services._models.privilege_assignment import ( + PrivilegeAssignment, +) from databricks_tests.core._resource_test_case import ResourceTestCase @@ -14,12 +17,14 @@ def _test_case(): add_resource=Resources.add_mcp_service, dict_example={ "config": {}, + "grants": [{}], "lifecycle": {}, "mcp_service_id": "mcp_service_id", "parent": "parent", }, dataclass_example=McpService( config=McpServiceConfig(), + grants=[PrivilegeAssignment()], lifecycle=Lifecycle(), mcp_service_id="mcp_service_id", parent="parent", diff --git a/python/databricks_tests/core/_generated/model_provider_services.py b/python/databricks_tests/core/_generated/model_provider_services.py index f91592daebb..994624aeee8 100644 --- a/python/databricks_tests/core/_generated/model_provider_services.py +++ b/python/databricks_tests/core/_generated/model_provider_services.py @@ -9,6 +9,9 @@ from databricks.bundles.model_provider_services._models.model_provider_service_config import ( ModelProviderServiceConfig, ) +from databricks.bundles.model_provider_services._models.privilege_assignment import ( + PrivilegeAssignment, +) from databricks_tests.core._resource_test_case import ResourceTestCase @@ -18,12 +21,14 @@ def _test_case(): add_resource=Resources.add_model_provider_service, dict_example={ "config": {}, + "grants": [{}], "lifecycle": {}, "model_provider_service_id": "model_provider_service_id", "parent": "parent", }, dataclass_example=ModelProviderService( config=ModelProviderServiceConfig(), + grants=[PrivilegeAssignment()], lifecycle=Lifecycle(), model_provider_service_id="model_provider_service_id", parent="parent", diff --git a/python/databricks_tests/core/_generated/model_services.py b/python/databricks_tests/core/_generated/model_services.py index 42ae3099700..5d301ae0203 100644 --- a/python/databricks_tests/core/_generated/model_services.py +++ b/python/databricks_tests/core/_generated/model_services.py @@ -7,6 +7,9 @@ from databricks.bundles.model_services._models.model_service_config import ( ModelServiceConfig, ) +from databricks.bundles.model_services._models.privilege_assignment import ( + PrivilegeAssignment, +) from databricks_tests.core._resource_test_case import ResourceTestCase @@ -16,12 +19,14 @@ def _test_case(): add_resource=Resources.add_model_service, dict_example={ "config": {}, + "grants": [{}], "lifecycle": {}, "model_service_id": "model_service_id", "parent": "parent", }, dataclass_example=ModelService( config=ModelServiceConfig(), + grants=[PrivilegeAssignment()], lifecycle=Lifecycle(), model_service_id="model_service_id", parent="parent", From dfd41f68ee3c880eb43b9c7ebeeea2519b9351c7 Mon Sep 17 00:00:00 2001 From: Alex Khakhlyuk Date: Mon, 14 Sep 2026 17:02:07 +0000 Subject: [PATCH 2/3] Rebase onto main: regenerate for databricks-sdk-go v0.178 Rebased the grants feature onto the v0.178 mps base. Regenerated the schema, validation, and pydabs outputs so the grants/permissions additions on the AI Gateway securables reflect the v0.178 spec (owner and request_tag dropped from model_services, mcp_services, and model_provider_services). Co-authored-by: Isaac --- bundle/internal/schema/annotations.yml | 6 ------ bundle/internal/validation/generated/enum_fields.go | 6 +++--- .../databricks/bundles/mcp_services/_models/privilege.py | 2 ++ .../bundles/model_provider_services/_models/privilege.py | 2 ++ python/databricks/bundles/model_services/__init__.py | 8 -------- .../bundles/model_services/_models/privilege.py | 2 ++ 6 files changed, 9 insertions(+), 17 deletions(-) diff --git a/bundle/internal/schema/annotations.yml b/bundle/internal/schema/annotations.yml index 8623362e990..e275e928478 100644 --- a/bundle/internal/schema/annotations.yml +++ b/bundle/internal/schema/annotations.yml @@ -1204,12 +1204,6 @@ resources: "config": "description": |- PLACEHOLDER - "$fields": - "source_connection": - "$fields": - "is_deleted": - "description": |- - PLACEHOLDER "grants": "description": |- PLACEHOLDER diff --git a/bundle/internal/validation/generated/enum_fields.go b/bundle/internal/validation/generated/enum_fields.go index cfa346ebd0a..75b0a6f9d6d 100644 --- a/bundle/internal/validation/generated/enum_fields.go +++ b/bundle/internal/validation/generated/enum_fields.go @@ -160,18 +160,18 @@ var EnumFields = map[string][]string{ "resources.mcp_services.*.config.rate_limits[*].key": {"RATE_LIMIT_KEY_SERVICE", "RATE_LIMIT_KEY_SERVICE_PRINCIPAL", "RATE_LIMIT_KEY_USER", "RATE_LIMIT_KEY_USER_DEFAULT", "RATE_LIMIT_KEY_USER_GROUP"}, "resources.mcp_services.*.config.rate_limits[*].renewal_period": {"RATE_LIMIT_RENEWAL_PERIOD_HOUR", "RATE_LIMIT_RENEWAL_PERIOD_MINUTE"}, - "resources.mcp_services.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_METADATA", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, + "resources.mcp_services.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_LOCATION", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_METADATA", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, "resources.model_provider_services.*.config.provider_type": {"EXTERNAL_MODEL_PROVIDER_TYPE_AMAZON_BEDROCK", "EXTERNAL_MODEL_PROVIDER_TYPE_ANTHROPIC", "EXTERNAL_MODEL_PROVIDER_TYPE_AZURE_OPENAI", "EXTERNAL_MODEL_PROVIDER_TYPE_CUSTOM", "EXTERNAL_MODEL_PROVIDER_TYPE_GEMINI_ENTERPRISE", "EXTERNAL_MODEL_PROVIDER_TYPE_MICROSOFT_FOUNDRY", "EXTERNAL_MODEL_PROVIDER_TYPE_OPENAI"}, "resources.model_provider_services.*.config.rate_limits[*].key": {"RATE_LIMIT_KEY_SERVICE", "RATE_LIMIT_KEY_SERVICE_PRINCIPAL", "RATE_LIMIT_KEY_USER", "RATE_LIMIT_KEY_USER_DEFAULT", "RATE_LIMIT_KEY_USER_GROUP"}, "resources.model_provider_services.*.config.rate_limits[*].renewal_period": {"RATE_LIMIT_RENEWAL_PERIOD_HOUR", "RATE_LIMIT_RENEWAL_PERIOD_MINUTE"}, - "resources.model_provider_services.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_METADATA", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, + "resources.model_provider_services.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_LOCATION", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_METADATA", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, "resources.model_services.*.config.rate_limits[*].key": {"RATE_LIMIT_KEY_SERVICE", "RATE_LIMIT_KEY_SERVICE_PRINCIPAL", "RATE_LIMIT_KEY_USER", "RATE_LIMIT_KEY_USER_DEFAULT", "RATE_LIMIT_KEY_USER_GROUP"}, "resources.model_services.*.config.rate_limits[*].renewal_period": {"RATE_LIMIT_RENEWAL_PERIOD_HOUR", "RATE_LIMIT_RENEWAL_PERIOD_MINUTE"}, "resources.model_services.*.config.routing.destinations[*].destination_type": {"DESTINATION_TYPE_EXTERNAL_FOUNDATION_MODEL", "DESTINATION_TYPE_PAY_PER_TOKEN_FOUNDATION_MODEL", "DESTINATION_TYPE_PROVISIONED_THROUGHPUT_FOUNDATION_MODEL"}, "resources.model_services.*.config.routing.fallback.destinations[*].destination_type": {"DESTINATION_TYPE_EXTERNAL_FOUNDATION_MODEL", "DESTINATION_TYPE_PAY_PER_TOKEN_FOUNDATION_MODEL", "DESTINATION_TYPE_PROVISIONED_THROUGHPUT_FOUNDATION_MODEL"}, - "resources.model_services.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_METADATA", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, + "resources.model_services.*.grants[*].privileges[*]": {"ACCESS", "ALL_PRIVILEGES", "APPLY_TAG", "BROWSE", "CREATE", "CREATE_CATALOG", "CREATE_CLEAN_ROOM", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FOREIGN_SECURABLE", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_PROVIDER", "CREATE_RECIPIENT", "CREATE_SCHEMA", "CREATE_SERVICE_CREDENTIAL", "CREATE_SHARE", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VIEW", "CREATE_VOLUME", "EXECUTE", "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_LOCATION", "EXTERNAL_USE_SCHEMA", "MANAGE", "MANAGE_ALLOWLIST", "MODIFY", "MODIFY_CLEAN_ROOM", "READ_FILES", "READ_METADATA", "READ_PRIVATE_FILES", "READ_VOLUME", "REFRESH", "SELECT", "SET_SHARE_PERMISSION", "USAGE", "USE_CATALOG", "USE_CONNECTION", "USE_MARKETPLACE_ASSETS", "USE_PROVIDER", "USE_RECIPIENT", "USE_SCHEMA", "USE_SHARE", "WRITE_FILES", "WRITE_PRIVATE_FILES", "WRITE_VOLUME"}, "resources.model_serving_endpoints.*.ai_gateway.guardrails.input.pii.behavior": {"BLOCK", "MASK", "NONE"}, "resources.model_serving_endpoints.*.ai_gateway.guardrails.output.pii.behavior": {"BLOCK", "MASK", "NONE"}, diff --git a/python/databricks/bundles/mcp_services/_models/privilege.py b/python/databricks/bundles/mcp_services/_models/privilege.py index 21a52a2f112..df45211a76a 100644 --- a/python/databricks/bundles/mcp_services/_models/privilege.py +++ b/python/databricks/bundles/mcp_services/_models/privilege.py @@ -56,6 +56,7 @@ class Privilege(Enum): EXECUTE_CLEAN_ROOM_TASK = "EXECUTE_CLEAN_ROOM_TASK" EXTERNAL_USE_SCHEMA = "EXTERNAL_USE_SCHEMA" READ_METADATA = "READ_METADATA" + EXTERNAL_USE_LOCATION = "EXTERNAL_USE_LOCATION" PrivilegeParam = ( @@ -111,6 +112,7 @@ class Privilege(Enum): "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "READ_METADATA", + "EXTERNAL_USE_LOCATION", ] | Privilege ) diff --git a/python/databricks/bundles/model_provider_services/_models/privilege.py b/python/databricks/bundles/model_provider_services/_models/privilege.py index 21a52a2f112..df45211a76a 100644 --- a/python/databricks/bundles/model_provider_services/_models/privilege.py +++ b/python/databricks/bundles/model_provider_services/_models/privilege.py @@ -56,6 +56,7 @@ class Privilege(Enum): EXECUTE_CLEAN_ROOM_TASK = "EXECUTE_CLEAN_ROOM_TASK" EXTERNAL_USE_SCHEMA = "EXTERNAL_USE_SCHEMA" READ_METADATA = "READ_METADATA" + EXTERNAL_USE_LOCATION = "EXTERNAL_USE_LOCATION" PrivilegeParam = ( @@ -111,6 +112,7 @@ class Privilege(Enum): "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "READ_METADATA", + "EXTERNAL_USE_LOCATION", ] | Privilege ) diff --git a/python/databricks/bundles/model_services/__init__.py b/python/databricks/bundles/model_services/__init__.py index b2e2f75719a..9e10e6df19c 100644 --- a/python/databricks/bundles/model_services/__init__.py +++ b/python/databricks/bundles/model_services/__init__.py @@ -34,9 +34,6 @@ "ModelServiceConfigRoutingConfig", "ModelServiceConfigRoutingConfigDict", "ModelServiceConfigRoutingConfigParam", - "ModelServiceConfigRoutingConfigTrafficSplitting", - "ModelServiceConfigRoutingConfigTrafficSplittingDict", - "ModelServiceConfigRoutingConfigTrafficSplittingParam", "ModelServiceDict", "ModelServiceParam", "Privilege", @@ -113,11 +110,6 @@ ModelServiceConfigRoutingConfigDict, ModelServiceConfigRoutingConfigParam, ) -from databricks.bundles.model_services._models.model_service_config_routing_config_traffic_splitting import ( - ModelServiceConfigRoutingConfigTrafficSplitting, - ModelServiceConfigRoutingConfigTrafficSplittingDict, - ModelServiceConfigRoutingConfigTrafficSplittingParam, -) from databricks.bundles.model_services._models.privilege import ( Privilege, PrivilegeParam, diff --git a/python/databricks/bundles/model_services/_models/privilege.py b/python/databricks/bundles/model_services/_models/privilege.py index 21a52a2f112..df45211a76a 100644 --- a/python/databricks/bundles/model_services/_models/privilege.py +++ b/python/databricks/bundles/model_services/_models/privilege.py @@ -56,6 +56,7 @@ class Privilege(Enum): EXECUTE_CLEAN_ROOM_TASK = "EXECUTE_CLEAN_ROOM_TASK" EXTERNAL_USE_SCHEMA = "EXTERNAL_USE_SCHEMA" READ_METADATA = "READ_METADATA" + EXTERNAL_USE_LOCATION = "EXTERNAL_USE_LOCATION" PrivilegeParam = ( @@ -111,6 +112,7 @@ class Privilege(Enum): "EXECUTE_CLEAN_ROOM_TASK", "EXTERNAL_USE_SCHEMA", "READ_METADATA", + "EXTERNAL_USE_LOCATION", ] | Privilege ) From 6a2b832c335e2f19e790ff2405d431934d260911 Mon Sep 17 00:00:00 2001 From: Alex Khakhlyuk Date: Tue, 15 Sep 2026 15:21:41 +0000 Subject: [PATCH 3/3] Fix grants goldens: correct uploaded-file count (5, not 7) The three AIG grants goldens recorded "Files: 7 uploaded" because they were regenerated locally without PYTHONDONTWRITEBYTECODE set, so two stray .pyc files got synced into the bundle. CI runs with PYTHONDONTWRITEBYTECODE=1 and uploads 5. Re-recorded with it set so the count matches CI. Only the file-count line changes. Co-authored-by: Isaac --- acceptance/bundle/resources/grants/mcp_services/output.txt | 2 +- .../bundle/resources/grants/model_provider_services/output.txt | 2 +- acceptance/bundle/resources/grants/model_services/output.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/acceptance/bundle/resources/grants/mcp_services/output.txt b/acceptance/bundle/resources/grants/mcp_services/output.txt index f3bd1e61625..1e2228fc501 100644 --- a/acceptance/bundle/resources/grants/mcp_services/output.txt +++ b/acceptance/bundle/resources/grants/mcp_services/output.txt @@ -7,7 +7,7 @@ Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-mcp-service-grants-[UNIQUE_NAME]/default/files... Created mcp_services.my_mcp_service Created mcp_services.my_mcp_service.grants -Files: 7 uploaded, 0 deleted +Files: 5 uploaded, 0 deleted Resources: 2 created, 0 changed, 0 deleted, 0 unchanged >>> print_requests.py //permissions diff --git a/acceptance/bundle/resources/grants/model_provider_services/output.txt b/acceptance/bundle/resources/grants/model_provider_services/output.txt index 350edf9f137..f4385a6de0b 100644 --- a/acceptance/bundle/resources/grants/model_provider_services/output.txt +++ b/acceptance/bundle/resources/grants/model_provider_services/output.txt @@ -7,7 +7,7 @@ Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-model-provider-service-grants-[UNIQUE_NAME]/default/files... Created model_provider_services.my_model_provider_service Created model_provider_services.my_model_provider_service.grants -Files: 7 uploaded, 0 deleted +Files: 5 uploaded, 0 deleted Resources: 2 created, 0 changed, 0 deleted, 0 unchanged >>> print_requests.py //permissions diff --git a/acceptance/bundle/resources/grants/model_services/output.txt b/acceptance/bundle/resources/grants/model_services/output.txt index e44df24529b..4ae40956b9b 100644 --- a/acceptance/bundle/resources/grants/model_services/output.txt +++ b/acceptance/bundle/resources/grants/model_services/output.txt @@ -7,7 +7,7 @@ Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/deploy-model-service-grants-[UNIQUE_NAME]/default/files... Created model_services.my_model_service Created model_services.my_model_service.grants -Files: 7 uploaded, 0 deleted +Files: 5 uploaded, 0 deleted Resources: 2 created, 0 changed, 0 deleted, 0 unchanged >>> print_requests.py //permissions