From f995c593477892fb3850534b31a3561838038a72 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 5 Mar 2026 11:09:02 +0100 Subject: [PATCH 01/15] Add analysis of grant types simplification --- ANALYSIS.md | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 ANALYSIS.md diff --git a/ANALYSIS.md b/ANALYSIS.md new file mode 100644 index 0000000000..86c4ff656a --- /dev/null +++ b/ANALYSIS.md @@ -0,0 +1,70 @@ +# Grant Types Simplification Analysis + +## Current State + +There are **5 custom Grant types** in `bundle/config/resources/`: + +| Type | Used by | Privilege type | +|------|---------|----------------| +| `Grant` (grant.go) | `RegisteredModel` | `[]string` | +| `SchemaGrant` | `Schema` | `[]SchemaGrantPrivilege` | +| `CatalogGrant` | `Catalog` | `[]CatalogGrantPrivilege` | +| `ExternalLocationGrant` | `ExternalLocation` | `[]ExternalLocationGrantPrivilege` | +| `VolumeGrant` | `Volume` | `[]VolumeGrantPrivilege` | + +Each resource-specific Grant type is paired with a `*GrantPrivilege` enum + `Values()` method +(e.g., `SchemaGrantPrivilege` with 16 constants). These are ~150 lines of boilerplate per resource type. + +There is also `GrantAssignment` in `bundle/direct/dresources/grants.go` which is essentially +`{ Principal string, Privileges []catalog.Privilege }`, plus reflection-based conversion from +the various Grant types to `GrantAssignment`. + +## SDK Type Available + +`catalog.PrivilegeAssignment` from the SDK has: + +```go +type PrivilegeAssignment struct { + Principal string `json:"principal,omitempty"` + Privileges []Privilege `json:"privileges,omitempty"` + ForceSendFields []string `json:"-"` +} +``` + +## Feasibility Analysis + +Replacing all custom Grant types with `catalog.PrivilegeAssignment` is possible, with tradeoffs: + +1. **Loss of per-resource privilege enums**: The resource-specific types (e.g., `SchemaGrantPrivilege`) + restrict which privileges appear in JSON schema documentation/validation. Using `catalog.Privilege` + gives the full superset. Users could put invalid privileges and only get errors at API call time. + +2. **JSON tag difference**: Custom types use `json:"privileges"` (no omitempty); SDK uses + `json:"privileges,omitempty"`. This could affect bundle YAML parsing behavior. + +3. **`Grant` is already inconsistent**: `RegisteredModel.Grants` uses `[]Grant` with + `Privileges []string` instead of typed privileges — it's already the odd one out. + +4. **`dresources.GrantAssignment`** could also be replaced with `catalog.PrivilegeAssignment` + directly, eliminating the reflection-based conversion in `PrepareGrantsInputConfig`. + +5. **Schema generation**: The tests in `schema_test.go` validate that the privilege enums match + SDK values — this test infrastructure would be simplified away. + +## Plan + +Replace all custom Grant types (`Grant`, `SchemaGrant`, `CatalogGrant`, `ExternalLocationGrant`, +`VolumeGrant`) with `catalog.PrivilegeAssignment`. Also replace `dresources.GrantAssignment` +with `catalog.PrivilegeAssignment` and remove the reflection-based conversion. + +Files affected: +- `bundle/config/resources/grant.go` — remove entirely +- `bundle/config/resources/schema.go` — remove `SchemaGrant*` types, use `catalog.PrivilegeAssignment` +- `bundle/config/resources/catalog.go` — remove `CatalogGrant*` types, use `catalog.PrivilegeAssignment` +- `bundle/config/resources/external_location.go` — remove `ExternalLocationGrant*` types +- `bundle/config/resources/volume.go` — remove `VolumeGrant*` types +- `bundle/config/resources/registered_model.go` — update `Grants` field type +- `bundle/direct/dresources/grants.go` — replace `GrantAssignment`, remove reflection conversion +- `bundle/config/resources/schema_test.go` — update/remove privilege exhaustiveness tests +- `bundle/config/resources/volume_test.go` — update tests +- Various test files referencing the old types From e6e135e977526d19bbc5de5ee5676a9e249e7787 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 5 Mar 2026 11:53:40 +0100 Subject: [PATCH 02/15] Replace custom Grant types with catalog.PrivilegeAssignment from SDK Removes five custom grant types (Grant, SchemaGrant, CatalogGrant, ExternalLocationGrant, VolumeGrant) and their associated per-resource privilege enums. All resources now use catalog.PrivilegeAssignment directly from the Databricks SDK. Also removes the reflection-based conversion in PrepareGrantsInputConfig replacing it with a simple type assertion, and removes the now-unnecessary TestSchemaGrantPrivilegesExhaustive test that maintained the enum sync. Co-Authored-By: Claude Sonnet 4.6 --- .claude/settings.local.json | 7 + bundle/config/resources/catalog.go | 71 +-- bundle/config/resources/external_location.go | 39 +- bundle/config/resources/grant.go | 9 - bundle/config/resources/registered_model.go | 5 +- bundle/config/resources/schema.go | 53 +-- bundle/config/resources/schema_test.go | 142 ------ bundle/config/resources/volume.go | 29 +- bundle/deploy/terraform/convert_test.go | 4 +- .../terraform/tfdyn/convert_grants_test.go | 9 +- .../tfdyn/convert_registered_model_test.go | 4 +- .../terraform/tfdyn/convert_schema_test.go | 14 +- .../terraform/tfdyn/convert_volume_test.go | 14 +- bundle/direct/dresources/all_test.go | 10 +- bundle/direct/dresources/grants.go | 75 +--- bundle/internal/schema/annotations.yml | 88 ---- .../schema/annotations_openapi_overrides.yml | 71 --- bundle/schema/jsonschema.json | 417 +++--------------- bundle/tests/registered_model_test.go | 3 +- 19 files changed, 111 insertions(+), 953 deletions(-) create mode 100644 .claude/settings.local.json delete mode 100644 bundle/config/resources/grant.go diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000000..c4f78ee52b --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(python3:*)" + ] + } +} diff --git a/bundle/config/resources/catalog.go b/bundle/config/resources/catalog.go index 94ede64a55..d558f127f5 100644 --- a/bundle/config/resources/catalog.go +++ b/bundle/config/resources/catalog.go @@ -13,81 +13,12 @@ import ( "github.com/databricks/cli/libs/log" ) -type CatalogGrantPrivilege string - -const ( - CatalogGrantPrivilegeAllPrivileges CatalogGrantPrivilege = "ALL_PRIVILEGES" - CatalogGrantPrivilegeApplyTag CatalogGrantPrivilege = "APPLY_TAG" - CatalogGrantPrivilegeCreateConnection CatalogGrantPrivilege = "CREATE_CONNECTION" - CatalogGrantPrivilegeCreateExternalLocation CatalogGrantPrivilege = "CREATE_EXTERNAL_LOCATION" - CatalogGrantPrivilegeCreateExternalTable CatalogGrantPrivilege = "CREATE_EXTERNAL_TABLE" - CatalogGrantPrivilegeCreateExternalVolume CatalogGrantPrivilege = "CREATE_EXTERNAL_VOLUME" - CatalogGrantPrivilegeCreateForeignCatalog CatalogGrantPrivilege = "CREATE_FOREIGN_CATALOG" - CatalogGrantPrivilegeCreateFunction CatalogGrantPrivilege = "CREATE_FUNCTION" - CatalogGrantPrivilegeCreateManagedStorage CatalogGrantPrivilege = "CREATE_MANAGED_STORAGE" - CatalogGrantPrivilegeCreateMaterializedView CatalogGrantPrivilege = "CREATE_MATERIALIZED_VIEW" - CatalogGrantPrivilegeCreateModel CatalogGrantPrivilege = "CREATE_MODEL" - CatalogGrantPrivilegeCreateSchema CatalogGrantPrivilege = "CREATE_SCHEMA" - CatalogGrantPrivilegeCreateStorageCredential CatalogGrantPrivilege = "CREATE_STORAGE_CREDENTIAL" - CatalogGrantPrivilegeCreateTable CatalogGrantPrivilege = "CREATE_TABLE" - CatalogGrantPrivilegeCreateVolume CatalogGrantPrivilege = "CREATE_VOLUME" - CatalogGrantPrivilegeExecute CatalogGrantPrivilege = "EXECUTE" - CatalogGrantPrivilegeManage CatalogGrantPrivilege = "MANAGE" - CatalogGrantPrivilegeModify CatalogGrantPrivilege = "MODIFY" - CatalogGrantPrivilegeReadVolume CatalogGrantPrivilege = "READ_VOLUME" - CatalogGrantPrivilegeRefresh CatalogGrantPrivilege = "REFRESH" - CatalogGrantPrivilegeSelect CatalogGrantPrivilege = "SELECT" - CatalogGrantPrivilegeUseCatalog CatalogGrantPrivilege = "USE_CATALOG" - CatalogGrantPrivilegeUseConnection CatalogGrantPrivilege = "USE_CONNECTION" - CatalogGrantPrivilegeUseSchema CatalogGrantPrivilege = "USE_SCHEMA" - CatalogGrantPrivilegeWriteVolume CatalogGrantPrivilege = "WRITE_VOLUME" -) - -// Values returns all valid CatalogGrantPrivilege values -func (CatalogGrantPrivilege) Values() []CatalogGrantPrivilege { - return []CatalogGrantPrivilege{ - CatalogGrantPrivilegeAllPrivileges, - CatalogGrantPrivilegeApplyTag, - CatalogGrantPrivilegeCreateConnection, - CatalogGrantPrivilegeCreateExternalLocation, - CatalogGrantPrivilegeCreateExternalTable, - CatalogGrantPrivilegeCreateExternalVolume, - CatalogGrantPrivilegeCreateForeignCatalog, - CatalogGrantPrivilegeCreateFunction, - CatalogGrantPrivilegeCreateManagedStorage, - CatalogGrantPrivilegeCreateMaterializedView, - CatalogGrantPrivilegeCreateModel, - CatalogGrantPrivilegeCreateSchema, - CatalogGrantPrivilegeCreateStorageCredential, - CatalogGrantPrivilegeCreateTable, - CatalogGrantPrivilegeCreateVolume, - CatalogGrantPrivilegeExecute, - CatalogGrantPrivilegeManage, - CatalogGrantPrivilegeModify, - CatalogGrantPrivilegeReadVolume, - CatalogGrantPrivilegeRefresh, - CatalogGrantPrivilegeSelect, - CatalogGrantPrivilegeUseCatalog, - CatalogGrantPrivilegeUseConnection, - CatalogGrantPrivilegeUseSchema, - CatalogGrantPrivilegeWriteVolume, - } -} - -// CatalogGrant holds the grant level settings for a single principal in Unity Catalog. -// Multiple of these can be defined on any catalog. -type CatalogGrant struct { - Privileges []CatalogGrantPrivilege `json:"privileges"` - - Principal string `json:"principal"` -} - type Catalog struct { BaseResource catalog.CreateCatalog // List of grants to apply on this catalog. - Grants []CatalogGrant `json:"grants,omitempty"` + Grants []catalog.PrivilegeAssignment `json:"grants,omitempty"` } func (c *Catalog) Exists(ctx context.Context, w *databricks.WorkspaceClient, name string) (bool, error) { diff --git a/bundle/config/resources/external_location.go b/bundle/config/resources/external_location.go index a44e9d7707..29cb5469d2 100644 --- a/bundle/config/resources/external_location.go +++ b/bundle/config/resources/external_location.go @@ -12,43 +12,6 @@ import ( "github.com/databricks/cli/libs/log" ) -type ExternalLocationGrantPrivilege string - -const ( - ExternalLocationGrantPrivilegeAllPrivileges ExternalLocationGrantPrivilege = "ALL_PRIVILEGES" - ExternalLocationGrantPrivilegeCreateExternalTable ExternalLocationGrantPrivilege = "CREATE_EXTERNAL_TABLE" - ExternalLocationGrantPrivilegeCreateExternalVolume ExternalLocationGrantPrivilege = "CREATE_EXTERNAL_VOLUME" - ExternalLocationGrantPrivilegeCreateManagedStorage ExternalLocationGrantPrivilege = "CREATE_MANAGED_STORAGE" - ExternalLocationGrantPrivilegeCreateTable ExternalLocationGrantPrivilege = "CREATE_TABLE" - ExternalLocationGrantPrivilegeCreateVolume ExternalLocationGrantPrivilege = "CREATE_VOLUME" - ExternalLocationGrantPrivilegeManage ExternalLocationGrantPrivilege = "MANAGE" - ExternalLocationGrantPrivilegeReadFiles ExternalLocationGrantPrivilege = "READ_FILES" - ExternalLocationGrantPrivilegeWriteFiles ExternalLocationGrantPrivilege = "WRITE_FILES" -) - -// Values returns all valid ExternalLocationGrantPrivilege values -func (ExternalLocationGrantPrivilege) Values() []ExternalLocationGrantPrivilege { - return []ExternalLocationGrantPrivilege{ - ExternalLocationGrantPrivilegeAllPrivileges, - ExternalLocationGrantPrivilegeCreateExternalTable, - ExternalLocationGrantPrivilegeCreateExternalVolume, - ExternalLocationGrantPrivilegeCreateManagedStorage, - ExternalLocationGrantPrivilegeCreateTable, - ExternalLocationGrantPrivilegeCreateVolume, - ExternalLocationGrantPrivilegeManage, - ExternalLocationGrantPrivilegeReadFiles, - ExternalLocationGrantPrivilegeWriteFiles, - } -} - -// ExternalLocationGrant holds the grant level settings for a single principal in Unity Catalog. -// Multiple of these can be defined on any external location. -type ExternalLocationGrant struct { - Privileges []ExternalLocationGrantPrivilege `json:"privileges"` - - Principal string `json:"principal"` -} - type ExternalLocation struct { // Manually include BaseResource fields to avoid URL field conflict ID string `json:"id,omitempty" bundle:"readonly"` @@ -59,7 +22,7 @@ type ExternalLocation struct { catalog.CreateExternalLocation // List of grants to apply on this external location. - Grants []ExternalLocationGrant `json:"grants,omitempty"` + Grants []catalog.PrivilegeAssignment `json:"grants,omitempty"` } func (e *ExternalLocation) Exists(ctx context.Context, w *databricks.WorkspaceClient, name string) (bool, error) { diff --git a/bundle/config/resources/grant.go b/bundle/config/resources/grant.go deleted file mode 100644 index f0ecd87674..0000000000 --- a/bundle/config/resources/grant.go +++ /dev/null @@ -1,9 +0,0 @@ -package resources - -// Grant holds the grant level settings for a single principal in Unity Catalog. -// Multiple of these can be defined on any Unity Catalog resource. -type Grant struct { - Privileges []string `json:"privileges"` - - Principal string `json:"principal"` -} diff --git a/bundle/config/resources/registered_model.go b/bundle/config/resources/registered_model.go index c8d82d08f1..c51450bf74 100644 --- a/bundle/config/resources/registered_model.go +++ b/bundle/config/resources/registered_model.go @@ -18,9 +18,8 @@ type RegisteredModel struct { // to a HCL representation for CRUD catalog.CreateRegisteredModelRequest - // This is a resource agnostic implementation of grants. - // Implementation could be different based on the resource type. - Grants []Grant `json:"grants,omitempty"` + // List of grants to apply on this registered model. + Grants []catalog.PrivilegeAssignment `json:"grants,omitempty"` } func (s *RegisteredModel) UnmarshalJSON(b []byte) error { diff --git a/bundle/config/resources/schema.go b/bundle/config/resources/schema.go index 124b1d940b..6cf4727279 100644 --- a/bundle/config/resources/schema.go +++ b/bundle/config/resources/schema.go @@ -14,62 +14,11 @@ import ( "github.com/databricks/databricks-sdk-go/service/catalog" ) -type SchemaGrantPrivilege string - -const ( - SchemaGrantPrivilegeAllPrivileges SchemaGrantPrivilege = "ALL_PRIVILEGES" - SchemaGrantPrivilegeApplyTag SchemaGrantPrivilege = "APPLY_TAG" - SchemaGrantPrivilegeCreateFunction SchemaGrantPrivilege = "CREATE_FUNCTION" - SchemaGrantPrivilegeCreateMaterializedView SchemaGrantPrivilege = "CREATE_MATERIALIZED_VIEW" - SchemaGrantPrivilegeCreateModel SchemaGrantPrivilege = "CREATE_MODEL" - SchemaGrantPrivilegeCreateTable SchemaGrantPrivilege = "CREATE_TABLE" - SchemaGrantPrivilegeCreateVolume SchemaGrantPrivilege = "CREATE_VOLUME" - SchemaGrantPrivilegeExecute SchemaGrantPrivilege = "EXECUTE" - SchemaGrantPrivilegeExternalUseSchema SchemaGrantPrivilege = "EXTERNAL_USE_SCHEMA" - SchemaGrantPrivilegeManage SchemaGrantPrivilege = "MANAGE" - SchemaGrantPrivilegeModify SchemaGrantPrivilege = "MODIFY" - SchemaGrantPrivilegeReadVolume SchemaGrantPrivilege = "READ_VOLUME" - SchemaGrantPrivilegeRefresh SchemaGrantPrivilege = "REFRESH" - SchemaGrantPrivilegeSelect SchemaGrantPrivilege = "SELECT" - SchemaGrantPrivilegeUseSchema SchemaGrantPrivilege = "USE_SCHEMA" - SchemaGrantPrivilegeWriteVolume SchemaGrantPrivilege = "WRITE_VOLUME" -) - -// Values returns all valid SchemaGrantPrivilege values -func (SchemaGrantPrivilege) Values() []SchemaGrantPrivilege { - return []SchemaGrantPrivilege{ - SchemaGrantPrivilegeAllPrivileges, - SchemaGrantPrivilegeApplyTag, - SchemaGrantPrivilegeCreateFunction, - SchemaGrantPrivilegeCreateMaterializedView, - SchemaGrantPrivilegeCreateModel, - SchemaGrantPrivilegeCreateTable, - SchemaGrantPrivilegeCreateVolume, - SchemaGrantPrivilegeExecute, - SchemaGrantPrivilegeExternalUseSchema, - SchemaGrantPrivilegeManage, - SchemaGrantPrivilegeModify, - SchemaGrantPrivilegeReadVolume, - SchemaGrantPrivilegeRefresh, - SchemaGrantPrivilegeSelect, - SchemaGrantPrivilegeUseSchema, - SchemaGrantPrivilegeWriteVolume, - } -} - -// SchemaGrant holds the grant level settings for a single principal in Unity Catalog. -// Multiple of these can be defined on any schema. -type SchemaGrant struct { - Privileges []SchemaGrantPrivilege `json:"privileges"` - - Principal string `json:"principal"` -} - type Schema struct { BaseResource catalog.CreateSchema // List of grants to apply on this schema. - Grants []SchemaGrant `json:"grants,omitempty"` + Grants []catalog.PrivilegeAssignment `json:"grants,omitempty"` } func (s *Schema) Exists(ctx context.Context, w *databricks.WorkspaceClient, fullName string) (bool, error) { diff --git a/bundle/config/resources/schema_test.go b/bundle/config/resources/schema_test.go index bb3d313fb2..55537062d5 100644 --- a/bundle/config/resources/schema_test.go +++ b/bundle/config/resources/schema_test.go @@ -1,14 +1,10 @@ package resources import ( - "fmt" - "sort" "testing" "github.com/databricks/databricks-sdk-go/apierr" "github.com/databricks/databricks-sdk-go/experimental/mocks" - "github.com/databricks/databricks-sdk-go/service/catalog" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) @@ -27,141 +23,3 @@ func TestSchemaNotFound(t *testing.T) { require.Falsef(t, exists, "Exists should return false when getting a 404 response from Workspace") require.NoErrorf(t, err, "Exists should not return an error when getting a 404 response from Workspace") } - -func TestSchemaGrantPrivilegesExhaustive(t *testing.T) { - // Privileges that are NOT valid for schemas and should be skipped. - // These are valid for other securable types (catalogs, connections, etc.) - // Source: https://docs.databricks.com/en/data-governance/unity-catalog/manage-privileges/privileges.html - skippedPrivileges := map[catalog.Privilege]string{ - // Catalog-level privileges - catalog.PrivilegeCreateCatalog: "catalog-level", - catalog.PrivilegeCreateSchema: "catalog-level", - catalog.PrivilegeUseCatalog: "catalog-level", - - // Connection-level privileges - catalog.PrivilegeCreateConnection: "connection-level", - catalog.PrivilegeUseConnection: "connection-level", - - // Storage-level privileges - catalog.PrivilegeCreateExternalLocation: "storage-level", - catalog.PrivilegeCreateExternalTable: "storage-level", - catalog.PrivilegeCreateExternalVolume: "storage-level", - catalog.PrivilegeCreateManagedStorage: "storage-level", - catalog.PrivilegeCreateStorageCredential: "storage-level", - catalog.PrivilegeReadFiles: "storage-level", - catalog.PrivilegeReadPrivateFiles: "storage-level", - catalog.PrivilegeWriteFiles: "storage-level", - catalog.PrivilegeWritePrivateFiles: "storage-level", - - // Metastore-level privileges - catalog.PrivilegeCreateProvider: "metastore-level", - catalog.PrivilegeCreateRecipient: "metastore-level", - catalog.PrivilegeCreateShare: "metastore-level", - catalog.PrivilegeManageAllowlist: "metastore-level", - catalog.PrivilegeUseProvider: "metastore-level", - catalog.PrivilegeUseRecipient: "metastore-level", - catalog.PrivilegeUseMarketplaceAssets: "metastore-level", - catalog.PrivilegeCreateServiceCredential: "metastore-level", - - // Share-level privileges - catalog.PrivilegeSetSharePermission: "share-level", - catalog.PrivilegeUseShare: "share-level", - - // Clean room-level privileges - catalog.PrivilegeCreateCleanRoom: "clean-room-level", - catalog.PrivilegeExecuteCleanRoomTask: "clean-room-level", - catalog.PrivilegeModifyCleanRoom: "clean-room-level", - - // Foreign securable privileges - catalog.PrivilegeCreateForeignCatalog: "foreign-securable", - catalog.PrivilegeCreateForeignSecurable: "foreign-securable", - - // Table/view-level privileges (not directly grantable on schema) - catalog.PrivilegeCreateView: "table-level", - - // Generic privileges that don't apply to schemas - catalog.PrivilegeAccess: "generic", - catalog.PrivilegeBrowse: "generic", - catalog.PrivilegeCreate: "generic", - catalog.PrivilegeUsage: "generic", - } - - // Get all SDK privileges dynamically - var p catalog.Privilege - sdkPrivileges := p.Values() - - // Get all privileges defined in our SchemaGrantPrivilege enum - definedPrivileges := SchemaGrantPrivilege("").Values() - definedPrivilegeMap := make(map[catalog.Privilege]bool) - for _, priv := range definedPrivileges { - definedPrivilegeMap[catalog.Privilege(priv)] = true - } - - // Build list of missing and unexpected privileges - var missingPrivileges []catalog.Privilege - var unexpectedPrivileges []catalog.Privilege - - // Check each SDK privilege - for _, sdkPriv := range sdkPrivileges { - isInDefined := definedPrivilegeMap[sdkPriv] - isInSkipList := skippedPrivileges[sdkPriv] != "" - - if !isInDefined && !isInSkipList { - // SDK has a privilege that we neither defined nor explicitly skipped - missingPrivileges = append(missingPrivileges, sdkPriv) - } - - if isInDefined && isInSkipList { - // We defined a privilege that's in the skip list (contradiction) - unexpectedPrivileges = append(unexpectedPrivileges, sdkPriv) - } - } - - // Check for privileges we defined that don't exist in SDK - sdkPrivilegeMap := make(map[catalog.Privilege]bool) - for _, priv := range sdkPrivileges { - sdkPrivilegeMap[priv] = true - } - - var invalidPrivileges []SchemaGrantPrivilege - for _, definedPriv := range definedPrivileges { - if !sdkPrivilegeMap[catalog.Privilege(definedPriv)] { - invalidPrivileges = append(invalidPrivileges, definedPriv) - } - } - - // Report errors - if len(missingPrivileges) > 0 { - sort.Slice(missingPrivileges, func(i, j int) bool { - return missingPrivileges[i] < missingPrivileges[j] - }) - assert.Fail(t, fmt.Sprintf( - "Found %d SDK privilege(s) that are not in SchemaGrantPrivilege and not in skip list.\n"+ - "If these privileges are valid for schemas, add them to SchemaGrantPrivilege in schema.go.\n"+ - "If they are NOT valid for schemas, add them to skippedPrivileges in schema_test.go.\n"+ - "Missing privileges: %v", - len(missingPrivileges), missingPrivileges)) - } - - if len(unexpectedPrivileges) > 0 { - sort.Slice(unexpectedPrivileges, func(i, j int) bool { - return unexpectedPrivileges[i] < unexpectedPrivileges[j] - }) - assert.Fail(t, fmt.Sprintf( - "Found %d privilege(s) that are both defined in SchemaGrantPrivilege AND in skip list.\n"+ - "This is a contradiction - remove them from either SchemaGrantPrivilege or the skip list.\n"+ - "Conflicting privileges: %v", - len(unexpectedPrivileges), unexpectedPrivileges)) - } - - if len(invalidPrivileges) > 0 { - sort.Slice(invalidPrivileges, func(i, j int) bool { - return invalidPrivileges[i] < invalidPrivileges[j] - }) - assert.Fail(t, fmt.Sprintf( - "Found %d privilege(s) in SchemaGrantPrivilege that don't exist in the SDK.\n"+ - "Remove these from SchemaGrantPrivilege in schema.go.\n"+ - "Invalid privileges: %v", - len(invalidPrivileges), invalidPrivileges)) - } -} diff --git a/bundle/config/resources/volume.go b/bundle/config/resources/volume.go index 8c47a6afc4..112f502066 100644 --- a/bundle/config/resources/volume.go +++ b/bundle/config/resources/volume.go @@ -13,39 +13,12 @@ import ( "github.com/databricks/databricks-sdk-go/service/catalog" ) -type VolumeGrantPrivilege string - -const ( - VolumeGrantPrivilegeAllPrivileges VolumeGrantPrivilege = "ALL_PRIVILEGES" - VolumeGrantPrivilegeApplyTag VolumeGrantPrivilege = "APPLY_TAG" - VolumeGrantPrivilegeManage VolumeGrantPrivilege = "MANAGE" - VolumeGrantPrivilegeReadVolume VolumeGrantPrivilege = "READ_VOLUME" - VolumeGrantPrivilegeWriteVolume VolumeGrantPrivilege = "WRITE_VOLUME" -) - -// Values returns all valid VolumeGrantPrivilege values -func (VolumeGrantPrivilege) Values() []VolumeGrantPrivilege { - return []VolumeGrantPrivilege{ - VolumeGrantPrivilegeAllPrivileges, - VolumeGrantPrivilegeApplyTag, - VolumeGrantPrivilegeManage, - VolumeGrantPrivilegeReadVolume, - VolumeGrantPrivilegeWriteVolume, - } -} - -type VolumeGrant struct { - Privileges []VolumeGrantPrivilege `json:"privileges"` - - Principal string `json:"principal"` -} - type Volume struct { BaseResource catalog.CreateVolumeRequestContent // List of grants to apply on this volume. - Grants []VolumeGrant `json:"grants,omitempty"` + Grants []catalog.PrivilegeAssignment `json:"grants,omitempty"` } func (v *Volume) UnmarshalJSON(b []byte) error { diff --git a/bundle/deploy/terraform/convert_test.go b/bundle/deploy/terraform/convert_test.go index ffec1cb7b1..564340190d 100644 --- a/bundle/deploy/terraform/convert_test.go +++ b/bundle/deploy/terraform/convert_test.go @@ -543,9 +543,9 @@ func TestBundleToTerraformRegisteredModelGrants(t *testing.T) { CatalogName: "catalog", SchemaName: "schema", }, - Grants: []resources.Grant{ + Grants: []catalog.PrivilegeAssignment{ { - Privileges: []string{"EXECUTE"}, + Privileges: []catalog.Privilege{catalog.PrivilegeExecute}, Principal: "jane@doe.com", }, }, diff --git a/bundle/deploy/terraform/tfdyn/convert_grants_test.go b/bundle/deploy/terraform/tfdyn/convert_grants_test.go index 9717529a86..6019ab823d 100644 --- a/bundle/deploy/terraform/tfdyn/convert_grants_test.go +++ b/bundle/deploy/terraform/tfdyn/convert_grants_test.go @@ -7,19 +7,20 @@ import ( "github.com/databricks/cli/bundle/internal/tf/schema" "github.com/databricks/cli/libs/dyn" "github.com/databricks/cli/libs/dyn/convert" + "github.com/databricks/databricks-sdk-go/service/catalog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestConvertGrants(t *testing.T) { src := resources.RegisteredModel{ - Grants: []resources.Grant{ + Grants: []catalog.PrivilegeAssignment{ { - Privileges: []string{"EXECUTE", "FOO"}, + Privileges: []catalog.Privilege{"EXECUTE", "FOO"}, Principal: "jane@doe.com", }, { - Privileges: []string{"EXECUTE", "BAR"}, + Privileges: []catalog.Privilege{"EXECUTE", "BAR"}, Principal: "spn", }, }, @@ -58,7 +59,7 @@ func TestConvertGrantsNil(t *testing.T) { func TestConvertGrantsEmpty(t *testing.T) { src := resources.RegisteredModel{ - Grants: []resources.Grant{}, + Grants: []catalog.PrivilegeAssignment{}, } vin, err := convert.FromTyped(src, dyn.NilValue) diff --git a/bundle/deploy/terraform/tfdyn/convert_registered_model_test.go b/bundle/deploy/terraform/tfdyn/convert_registered_model_test.go index 04bf331502..dab20f45eb 100644 --- a/bundle/deploy/terraform/tfdyn/convert_registered_model_test.go +++ b/bundle/deploy/terraform/tfdyn/convert_registered_model_test.go @@ -20,9 +20,9 @@ func TestConvertRegisteredModel(t *testing.T) { SchemaName: "schema", Comment: "comment", }, - Grants: []resources.Grant{ + Grants: []catalog.PrivilegeAssignment{ { - Privileges: []string{"EXECUTE"}, + Privileges: []catalog.Privilege{catalog.PrivilegeExecute}, Principal: "jane@doe.com", }, }, diff --git a/bundle/deploy/terraform/tfdyn/convert_schema_test.go b/bundle/deploy/terraform/tfdyn/convert_schema_test.go index ec738d3ef0..1d2431a5e1 100644 --- a/bundle/deploy/terraform/tfdyn/convert_schema_test.go +++ b/bundle/deploy/terraform/tfdyn/convert_schema_test.go @@ -24,18 +24,14 @@ func TestConvertSchema(t *testing.T) { }, StorageRoot: "root", }, - Grants: []resources.SchemaGrant{ + Grants: []catalog.PrivilegeAssignment{ { - Privileges: []resources.SchemaGrantPrivilege{ - resources.SchemaGrantPrivilegeExecute, - }, - Principal: "jack@gmail.com", + Privileges: []catalog.Privilege{catalog.PrivilegeExecute}, + Principal: "jack@gmail.com", }, { - Privileges: []resources.SchemaGrantPrivilege{ - resources.SchemaGrantPrivilegeSelect, - }, - Principal: "jane@gmail.com", + Privileges: []catalog.Privilege{catalog.PrivilegeSelect}, + Principal: "jane@gmail.com", }, }, } diff --git a/bundle/deploy/terraform/tfdyn/convert_volume_test.go b/bundle/deploy/terraform/tfdyn/convert_volume_test.go index 6eb344853d..bd8798780a 100644 --- a/bundle/deploy/terraform/tfdyn/convert_volume_test.go +++ b/bundle/deploy/terraform/tfdyn/convert_volume_test.go @@ -22,18 +22,14 @@ func TestConvertVolume(t *testing.T) { StorageLocation: "s3://bucket/path", VolumeType: "EXTERNAL", }, - Grants: []resources.VolumeGrant{ + Grants: []catalog.PrivilegeAssignment{ { - Privileges: []resources.VolumeGrantPrivilege{ - resources.VolumeGrantPrivilegeReadVolume, - }, - Principal: "jack@gmail.com", + Privileges: []catalog.Privilege{catalog.PrivilegeReadVolume}, + Principal: "jack@gmail.com", }, { - Privileges: []resources.VolumeGrantPrivilege{ - resources.VolumeGrantPrivilegeWriteVolume, - }, - Principal: "jane@gmail.com", + Privileges: []catalog.Privilege{catalog.PrivilegeWriteVolume}, + Principal: "jane@gmail.com", }, }, } diff --git a/bundle/direct/dresources/all_test.go b/bundle/direct/dresources/all_test.go index 124d9a4ec9..0c3d95da8a 100644 --- a/bundle/direct/dresources/all_test.go +++ b/bundle/direct/dresources/all_test.go @@ -509,7 +509,7 @@ var testDeps = map[string]prepareWorkspace{ return &GrantsState{ SecurableType: "catalog", FullName: "mycatalog", - Grants: []GrantAssignment{{ + Grants: []catalog.PrivilegeAssignment{{ Privileges: []catalog.Privilege{catalog.PrivilegeUseCatalog}, Principal: "user@example.com", }}, @@ -520,7 +520,7 @@ var testDeps = map[string]prepareWorkspace{ return &GrantsState{ SecurableType: "external_location", FullName: "myexternallocation", - Grants: []GrantAssignment{{ + Grants: []catalog.PrivilegeAssignment{{ Privileges: []catalog.Privilege{catalog.PrivilegeReadFiles}, Principal: "user@example.com", }}, @@ -531,7 +531,7 @@ var testDeps = map[string]prepareWorkspace{ return &GrantsState{ SecurableType: "schema", FullName: "main.myschema", - Grants: []GrantAssignment{{ + Grants: []catalog.PrivilegeAssignment{{ Privileges: []catalog.Privilege{catalog.PrivilegeCreateView}, Principal: "user@example.com", }}, @@ -542,7 +542,7 @@ var testDeps = map[string]prepareWorkspace{ return &GrantsState{ SecurableType: "volume", FullName: "main.myschema.myvolume", - Grants: []GrantAssignment{{ + Grants: []catalog.PrivilegeAssignment{{ Privileges: []catalog.Privilege{catalog.PrivilegeCreateView}, Principal: "user@example.com", }}, @@ -553,7 +553,7 @@ var testDeps = map[string]prepareWorkspace{ return &GrantsState{ SecurableType: "registered-model", FullName: "modelid", - Grants: []GrantAssignment{{ + Grants: []catalog.PrivilegeAssignment{{ Privileges: []catalog.Privilege{catalog.PrivilegeCreateView}, Principal: "user@example.com", }}, diff --git a/bundle/direct/dresources/grants.go b/bundle/direct/dresources/grants.go index 76e504e5a0..8c0989aa99 100644 --- a/bundle/direct/dresources/grants.go +++ b/bundle/direct/dresources/grants.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "reflect" "sort" "strings" @@ -21,15 +20,10 @@ var grantResourceToSecurableType = map[string]string{ "registered_models": "function", } -type GrantAssignment struct { - Principal string `json:"principal"` - Privileges []catalog.Privilege `json:"privileges,omitempty"` -} - type GrantsState struct { - SecurableType string `json:"securable_type"` - FullName string `json:"full_name"` - Grants []GrantAssignment `json:"grants,omitempty"` + SecurableType string `json:"securable_type"` + FullName string `json:"full_name"` + Grants []catalog.PrivilegeAssignment `json:"grants,omitempty"` } func PrepareGrantsInputConfig(inputConfig any, node string) (*structvar.StructVar, error) { @@ -48,59 +42,21 @@ func PrepareGrantsInputConfig(inputConfig any, node string) (*structvar.StructVa return nil, fmt.Errorf("unsupported grants resource type: %s", resourceType) } - rv := reflect.ValueOf(inputConfig) - if rv.Kind() != reflect.Ptr || rv.Elem().Kind() != reflect.Slice { - return nil, fmt.Errorf("inputConfig must be a pointer to a slice, got: %T", inputConfig) + grantsPtr, ok := inputConfig.(*[]catalog.PrivilegeAssignment) + if !ok { + return nil, fmt.Errorf("expected *[]catalog.PrivilegeAssignment, got %T", inputConfig) } - sliceValue := rv.Elem() - grants := make([]GrantAssignment, 0, sliceValue.Len()) - for i := range sliceValue.Len() { - elem := sliceValue.Index(i) - if elem.Kind() == reflect.Ptr { - elem = elem.Elem() - } - if elem.Kind() != reflect.Struct { - return nil, fmt.Errorf("grant element must be a struct, got %s", elem.Kind()) - } - - principalField := elem.FieldByName("Principal") - if !principalField.IsValid() { - return nil, errors.New("grant element missing Principal field") - } - principal := principalField.String() - - privilegesField := elem.FieldByName("Privileges") - if !privilegesField.IsValid() { - return nil, errors.New("grant element missing Privileges field") - } - if privilegesField.Kind() != reflect.Slice { - return nil, errors.New("grant Privileges field must be a slice") - } - - privileges := make([]catalog.Privilege, 0, privilegesField.Len()) - for j := range privilegesField.Len() { - item := privilegesField.Index(j) - if item.Kind() != reflect.String { - return nil, fmt.Errorf("privilege must be a string, got %s", item.Kind()) - } - privileges = append(privileges, catalog.Privilege(item.String())) - } - - // Backend sorts privileges, so we sort here as well. - sortPriviliges(privileges) - - grants = append(grants, GrantAssignment{ - Principal: principal, - Privileges: privileges, - }) + // Backend sorts privileges, so we sort here as well. + for i := range *grantsPtr { + sortPriviliges((*grantsPtr)[i].Privileges) } return &structvar.StructVar{ Value: &GrantsState{ SecurableType: securableType, FullName: "", - Grants: grants, + Grants: *grantsPtr, }, Refs: map[string]string{ "full_name": "${" + baseNode + ".id}", @@ -182,8 +138,8 @@ func (r *ResourceGrants) applyGrants(ctx context.Context, state *GrantsState) er return err } -func (r *ResourceGrants) listGrants(ctx context.Context, securableType, fullName string) ([]GrantAssignment, error) { - var assignments []GrantAssignment +func (r *ResourceGrants) listGrants(ctx context.Context, securableType, fullName string) ([]catalog.PrivilegeAssignment, error) { + var assignments []catalog.PrivilegeAssignment pageToken := "" for { resp, err := r.client.Grants.Get(ctx, catalog.GetGrantRequest{ @@ -203,9 +159,10 @@ func (r *ResourceGrants) listGrants(ctx context.Context, securableType, fullName } privs := make([]catalog.Privilege, len(assignment.Privileges)) copy(privs, assignment.Privileges) - assignments = append(assignments, GrantAssignment{ - Principal: assignment.Principal, - Privileges: privs, + assignments = append(assignments, catalog.PrivilegeAssignment{ + Principal: assignment.Principal, + Privileges: privs, + ForceSendFields: nil, }) } if resp.NextPageToken == "" { diff --git a/bundle/internal/schema/annotations.yml b/bundle/internal/schema/annotations.yml index 8b4817bd4f..e5b3ccd0dd 100644 --- a/bundle/internal/schema/annotations.yml +++ b/bundle/internal/schema/annotations.yml @@ -583,66 +583,6 @@ github.com/databricks/cli/bundle/config/resources.Catalog: "storage_root": "description": |- PLACEHOLDER -github.com/databricks/cli/bundle/config/resources.CatalogGrant: - "principal": - "description": |- - PLACEHOLDER - "privileges": - "description": |- - PLACEHOLDER -github.com/databricks/cli/bundle/config/resources.CatalogGrantPrivilege: - "_": - "enum": - - |- - ALL_PRIVILEGES - - |- - APPLY_TAG - - |- - CREATE_CONNECTION - - |- - CREATE_EXTERNAL_LOCATION - - |- - CREATE_EXTERNAL_TABLE - - |- - CREATE_EXTERNAL_VOLUME - - |- - CREATE_FOREIGN_CATALOG - - |- - CREATE_FUNCTION - - |- - CREATE_MANAGED_STORAGE - - |- - CREATE_MATERIALIZED_VIEW - - |- - CREATE_MODEL - - |- - CREATE_SCHEMA - - |- - CREATE_STORAGE_CREDENTIAL - - |- - CREATE_TABLE - - |- - CREATE_VOLUME - - |- - EXECUTE - - |- - MANAGE - - |- - MODIFY - - |- - READ_VOLUME - - |- - REFRESH - - |- - SELECT - - |- - USE_CATALOG - - |- - USE_CONNECTION - - |- - USE_SCHEMA - - |- - WRITE_VOLUME github.com/databricks/cli/bundle/config/resources.ClusterPermission: "group_name": "description": |- @@ -743,20 +683,6 @@ github.com/databricks/cli/bundle/config/resources.ExternalLocation: "url": "description": |- PLACEHOLDER -github.com/databricks/cli/bundle/config/resources.ExternalLocationGrant: - "principal": - "description": |- - PLACEHOLDER - "privileges": - "description": |- - PLACEHOLDER -github.com/databricks/cli/bundle/config/resources.Grant: - "principal": - "description": |- - The name of the principal that will be granted privileges - "privileges": - "description": |- - The privileges to grant to the specified entity github.com/databricks/cli/bundle/config/resources.JobPermission: "group_name": "description": |- @@ -991,13 +917,6 @@ github.com/databricks/cli/bundle/config/resources.PostgresProject: "update_time": "description": |- PLACEHOLDER -github.com/databricks/cli/bundle/config/resources.SchemaGrant: - "principal": - "description": |- - PLACEHOLDER - "privileges": - "description": |- - PLACEHOLDER github.com/databricks/cli/bundle/config/resources.SecretScope: "backend_type": "description": |- @@ -1065,13 +984,6 @@ github.com/databricks/cli/bundle/config/resources.SyncedDatabaseTable: "unity_catalog_provisioning_state": "description": |- PLACEHOLDER -github.com/databricks/cli/bundle/config/resources.VolumeGrant: - "principal": - "description": |- - PLACEHOLDER - "privileges": - "description": |- - PLACEHOLDER github.com/databricks/cli/bundle/config/variable.Lookup: "alert": "description": |- diff --git a/bundle/internal/schema/annotations_openapi_overrides.yml b/bundle/internal/schema/annotations_openapi_overrides.yml index baf54f2af6..4aaab347e0 100644 --- a/bundle/internal/schema/annotations_openapi_overrides.yml +++ b/bundle/internal/schema/annotations_openapi_overrides.yml @@ -277,29 +277,6 @@ github.com/databricks/cli/bundle/config/resources.ExternalLocation: "lifecycle": "description": |- PLACEHOLDER -github.com/databricks/cli/bundle/config/resources.ExternalLocationGrantPrivilege: - "_": - "description": |- - Privilege to grant on an external location - "enum": - - |- - ALL_PRIVILEGES - - |- - CREATE_EXTERNAL_TABLE - - |- - CREATE_EXTERNAL_VOLUME - - |- - CREATE_MANAGED_STORAGE - - |- - CREATE_TABLE - - |- - CREATE_VOLUME - - |- - MANAGE - - |- - READ_FILES - - |- - WRITE_FILES github.com/databricks/cli/bundle/config/resources.Job: "_": "markdown_description": |- @@ -634,41 +611,6 @@ github.com/databricks/cli/bundle/config/resources.Schema: "properties": "description": |- PLACEHOLDER -github.com/databricks/cli/bundle/config/resources.SchemaGrantPrivilege: - "_": - "enum": - - |- - ALL_PRIVILEGES - - |- - APPLY_TAG - - |- - CREATE_FUNCTION - - |- - CREATE_MATERIALIZED_VIEW - - |- - CREATE_MODEL - - |- - CREATE_TABLE - - |- - CREATE_VOLUME - - |- - EXECUTE - - |- - EXTERNAL_USE_SCHEMA - - |- - MANAGE - - |- - MODIFY - - |- - READ_VOLUME - - |- - REFRESH - - |- - SELECT - - |- - USE_SCHEMA - - |- - WRITE_VOLUME github.com/databricks/cli/bundle/config/resources.SecretScopePermissionLevel: "_": "enum": @@ -741,19 +683,6 @@ github.com/databricks/cli/bundle/config/resources.Volume: "volume_type": "description": |- PLACEHOLDER -github.com/databricks/cli/bundle/config/resources.VolumeGrantPrivilege: - "_": - "enum": - - |- - ALL_PRIVILEGES - - |- - APPLY_TAG - - |- - MANAGE - - |- - READ_VOLUME - - |- - WRITE_VOLUME github.com/databricks/databricks-sdk-go/service/apps.AppDeployment: "create_time": "description": |- diff --git a/bundle/schema/jsonschema.json b/bundle/schema/jsonschema.json index 2f48fb85f9..e6d265bb20 100644 --- a/bundle/schema/jsonschema.json +++ b/bundle/schema/jsonschema.json @@ -339,7 +339,7 @@ "$ref": "#/$defs/string" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.CatalogGrant" + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" }, "lifecycle": { "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle" @@ -374,68 +374,6 @@ } ] }, - "resources.CatalogGrant": { - "oneOf": [ - { - "type": "object", - "properties": { - "principal": { - "$ref": "#/$defs/string" - }, - "privileges": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.CatalogGrantPrivilege" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.CatalogGrantPrivilege": { - "oneOf": [ - { - "type": "string", - "enum": [ - "ALL_PRIVILEGES", - "APPLY_TAG", - "CREATE_CONNECTION", - "CREATE_EXTERNAL_LOCATION", - "CREATE_EXTERNAL_TABLE", - "CREATE_EXTERNAL_VOLUME", - "CREATE_FOREIGN_CATALOG", - "CREATE_FUNCTION", - "CREATE_MANAGED_STORAGE", - "CREATE_MATERIALIZED_VIEW", - "CREATE_MODEL", - "CREATE_SCHEMA", - "CREATE_STORAGE_CREDENTIAL", - "CREATE_TABLE", - "CREATE_VOLUME", - "EXECUTE", - "MANAGE", - "MODIFY", - "READ_VOLUME", - "REFRESH", - "SELECT", - "USE_CATALOG", - "USE_CONNECTION", - "USE_SCHEMA", - "WRITE_VOLUME" - ] - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, "resources.Cluster": { "oneOf": [ { @@ -973,7 +911,7 @@ "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/catalog.FileEventQueue" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.ExternalLocationGrant" + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" }, "lifecycle": { "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle" @@ -1004,79 +942,6 @@ } ] }, - "resources.ExternalLocationGrant": { - "oneOf": [ - { - "type": "object", - "properties": { - "principal": { - "$ref": "#/$defs/string" - }, - "privileges": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.ExternalLocationGrantPrivilege" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.ExternalLocationGrantPrivilege": { - "oneOf": [ - { - "type": "string", - "description": "Privilege to grant on an external location", - "enum": [ - "ALL_PRIVILEGES", - "CREATE_EXTERNAL_TABLE", - "CREATE_EXTERNAL_VOLUME", - "CREATE_MANAGED_STORAGE", - "CREATE_TABLE", - "CREATE_VOLUME", - "MANAGE", - "READ_FILES", - "WRITE_FILES" - ] - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.Grant": { - "oneOf": [ - { - "type": "object", - "properties": { - "principal": { - "description": "The name of the principal that will be granted privileges", - "$ref": "#/$defs/string" - }, - "privileges": { - "description": "The privileges to grant to the specified entity", - "$ref": "#/$defs/slice/string" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, "resources.Job": { "oneOf": [ { @@ -2007,7 +1872,7 @@ "$ref": "#/$defs/string" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.Grant" + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" }, "lifecycle": { "description": "Lifecycle is a struct that contains the lifecycle settings for a resource. It controls the behavior of the resource when it is deployed or destroyed.", @@ -2061,7 +1926,7 @@ "$ref": "#/$defs/string" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.SchemaGrant" + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" }, "lifecycle": { "description": "Lifecycle is a struct that contains the lifecycle settings for a resource. It controls the behavior of the resource when it is deployed or destroyed.", @@ -2092,59 +1957,6 @@ } ] }, - "resources.SchemaGrant": { - "oneOf": [ - { - "type": "object", - "properties": { - "principal": { - "$ref": "#/$defs/string" - }, - "privileges": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.SchemaGrantPrivilege" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.SchemaGrantPrivilege": { - "oneOf": [ - { - "type": "string", - "enum": [ - "ALL_PRIVILEGES", - "APPLY_TAG", - "CREATE_FUNCTION", - "CREATE_MATERIALIZED_VIEW", - "CREATE_MODEL", - "CREATE_TABLE", - "CREATE_VOLUME", - "EXECUTE", - "EXTERNAL_USE_SCHEMA", - "MANAGE", - "MODIFY", - "READ_VOLUME", - "REFRESH", - "SELECT", - "USE_SCHEMA", - "WRITE_VOLUME" - ] - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, "resources.SecretScope": { "oneOf": [ { @@ -2398,7 +2210,7 @@ "$ref": "#/$defs/string" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.VolumeGrant" + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" }, "lifecycle": { "description": "Lifecycle is a struct that contains the lifecycle settings for a resource. It controls the behavior of the resource when it is deployed or destroyed.", @@ -2434,48 +2246,6 @@ } ] }, - "resources.VolumeGrant": { - "oneOf": [ - { - "type": "object", - "properties": { - "principal": { - "$ref": "#/$defs/string" - }, - "privileges": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.VolumeGrantPrivilege" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.VolumeGrantPrivilege": { - "oneOf": [ - { - "type": "string", - "enum": [ - "ALL_PRIVILEGES", - "APPLY_TAG", - "MANAGE", - "READ_VOLUME", - "WRITE_VOLUME" - ] - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, "variable.Lookup": { "oneOf": [ { @@ -4314,6 +4084,29 @@ } ] }, + "catalog.Privilege": { + "type": "string" + }, + "catalog.PrivilegeAssignment": { + "oneOf": [ + { + "type": "object", + "properties": { + "principal": { + "$ref": "#/$defs/string" + }, + "privileges": { + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.Privilege" + } + }, + "additionalProperties": false + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] + }, "catalog.RegisteredModelAlias": { "oneOf": [ { @@ -11165,34 +10958,6 @@ } ] }, - "resources.CatalogGrant": { - "oneOf": [ - { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.CatalogGrant" - } - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.CatalogGrantPrivilege": { - "oneOf": [ - { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.CatalogGrantPrivilege" - } - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, "resources.ClusterPermission": { "oneOf": [ { @@ -11249,48 +11014,6 @@ } ] }, - "resources.ExternalLocationGrant": { - "oneOf": [ - { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.ExternalLocationGrant" - } - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.ExternalLocationGrantPrivilege": { - "oneOf": [ - { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.ExternalLocationGrantPrivilege" - } - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.Grant": { - "oneOf": [ - { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Grant" - } - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, "resources.JobPermission": { "oneOf": [ { @@ -11375,34 +11098,6 @@ } ] }, - "resources.SchemaGrant": { - "oneOf": [ - { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.SchemaGrant" - } - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.SchemaGrantPrivilege": { - "oneOf": [ - { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.SchemaGrantPrivilege" - } - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, "resources.SecretScopePermission": { "oneOf": [ { @@ -11430,34 +11125,6 @@ "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" } ] - }, - "resources.VolumeGrant": { - "oneOf": [ - { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.VolumeGrant" - } - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] - }, - "resources.VolumeGrantPrivilege": { - "oneOf": [ - { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.VolumeGrantPrivilege" - } - }, - { - "type": "string", - "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" - } - ] } }, "config.ArtifactFile": { @@ -11520,6 +11187,34 @@ } ] }, + "catalog.Privilege": { + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/catalog.Privilege" + } + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] + }, + "catalog.PrivilegeAssignment": { + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" + } + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] + }, "catalog.RegisteredModelAlias": { "oneOf": [ { diff --git a/bundle/tests/registered_model_test.go b/bundle/tests/registered_model_test.go index e9d572a3a3..ce11656efc 100644 --- a/bundle/tests/registered_model_test.go +++ b/bundle/tests/registered_model_test.go @@ -5,6 +5,7 @@ import ( "github.com/databricks/cli/bundle/config" "github.com/databricks/cli/bundle/config/resources" + "github.com/databricks/databricks-sdk-go/service/catalog" "github.com/stretchr/testify/assert" ) @@ -13,7 +14,7 @@ func assertExpectedModel(t *testing.T, p *resources.RegisteredModel) { assert.Equal(t, "default", p.SchemaName) assert.Equal(t, "comment", p.Comment) assert.Equal(t, "account users", p.Grants[0].Principal) - assert.Equal(t, "EXECUTE", p.Grants[0].Privileges[0]) + assert.Equal(t, catalog.Privilege("EXECUTE"), p.Grants[0].Privileges[0]) } func TestRegisteredModelDevelopment(t *testing.T) { From 1c7ecea4dad0fcaf1d1aad6e0b4097ae858009a6 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 5 Mar 2026 11:54:26 +0100 Subject: [PATCH 03/15] Remove ANALYSIS.md --- ANALYSIS.md | 70 ----------------------------------------------------- 1 file changed, 70 deletions(-) delete mode 100644 ANALYSIS.md diff --git a/ANALYSIS.md b/ANALYSIS.md deleted file mode 100644 index 86c4ff656a..0000000000 --- a/ANALYSIS.md +++ /dev/null @@ -1,70 +0,0 @@ -# Grant Types Simplification Analysis - -## Current State - -There are **5 custom Grant types** in `bundle/config/resources/`: - -| Type | Used by | Privilege type | -|------|---------|----------------| -| `Grant` (grant.go) | `RegisteredModel` | `[]string` | -| `SchemaGrant` | `Schema` | `[]SchemaGrantPrivilege` | -| `CatalogGrant` | `Catalog` | `[]CatalogGrantPrivilege` | -| `ExternalLocationGrant` | `ExternalLocation` | `[]ExternalLocationGrantPrivilege` | -| `VolumeGrant` | `Volume` | `[]VolumeGrantPrivilege` | - -Each resource-specific Grant type is paired with a `*GrantPrivilege` enum + `Values()` method -(e.g., `SchemaGrantPrivilege` with 16 constants). These are ~150 lines of boilerplate per resource type. - -There is also `GrantAssignment` in `bundle/direct/dresources/grants.go` which is essentially -`{ Principal string, Privileges []catalog.Privilege }`, plus reflection-based conversion from -the various Grant types to `GrantAssignment`. - -## SDK Type Available - -`catalog.PrivilegeAssignment` from the SDK has: - -```go -type PrivilegeAssignment struct { - Principal string `json:"principal,omitempty"` - Privileges []Privilege `json:"privileges,omitempty"` - ForceSendFields []string `json:"-"` -} -``` - -## Feasibility Analysis - -Replacing all custom Grant types with `catalog.PrivilegeAssignment` is possible, with tradeoffs: - -1. **Loss of per-resource privilege enums**: The resource-specific types (e.g., `SchemaGrantPrivilege`) - restrict which privileges appear in JSON schema documentation/validation. Using `catalog.Privilege` - gives the full superset. Users could put invalid privileges and only get errors at API call time. - -2. **JSON tag difference**: Custom types use `json:"privileges"` (no omitempty); SDK uses - `json:"privileges,omitempty"`. This could affect bundle YAML parsing behavior. - -3. **`Grant` is already inconsistent**: `RegisteredModel.Grants` uses `[]Grant` with - `Privileges []string` instead of typed privileges — it's already the odd one out. - -4. **`dresources.GrantAssignment`** could also be replaced with `catalog.PrivilegeAssignment` - directly, eliminating the reflection-based conversion in `PrepareGrantsInputConfig`. - -5. **Schema generation**: The tests in `schema_test.go` validate that the privilege enums match - SDK values — this test infrastructure would be simplified away. - -## Plan - -Replace all custom Grant types (`Grant`, `SchemaGrant`, `CatalogGrant`, `ExternalLocationGrant`, -`VolumeGrant`) with `catalog.PrivilegeAssignment`. Also replace `dresources.GrantAssignment` -with `catalog.PrivilegeAssignment` and remove the reflection-based conversion. - -Files affected: -- `bundle/config/resources/grant.go` — remove entirely -- `bundle/config/resources/schema.go` — remove `SchemaGrant*` types, use `catalog.PrivilegeAssignment` -- `bundle/config/resources/catalog.go` — remove `CatalogGrant*` types, use `catalog.PrivilegeAssignment` -- `bundle/config/resources/external_location.go` — remove `ExternalLocationGrant*` types -- `bundle/config/resources/volume.go` — remove `VolumeGrant*` types -- `bundle/config/resources/registered_model.go` — update `Grants` field type -- `bundle/direct/dresources/grants.go` — replace `GrantAssignment`, remove reflection conversion -- `bundle/config/resources/schema_test.go` — update/remove privilege exhaustiveness tests -- `bundle/config/resources/volume_test.go` — update tests -- Various test files referencing the old types From d2f989ddd73a5c81f972877f2babd57b48aebe2a Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 5 Mar 2026 12:32:17 +0100 Subject: [PATCH 04/15] Remove .claude/settings.local.json --- .claude/settings.local.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index c4f78ee52b..0000000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(python3:*)" - ] - } -} From 7922331fd6f40dbd8afd00d62f652ee93e7a5f26 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 5 Mar 2026 12:43:07 +0100 Subject: [PATCH 05/15] Update refschema --- acceptance/bundle/refschema/out.fields.txt | 60 +++++++++++----------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/acceptance/bundle/refschema/out.fields.txt b/acceptance/bundle/refschema/out.fields.txt index f401945572..0d57557d8d 100644 --- a/acceptance/bundle/refschema/out.fields.txt +++ b/acceptance/bundle/refschema/out.fields.txt @@ -233,11 +233,11 @@ resources.catalogs.*.effective_predictive_optimization_flag.inherited_from_type resources.catalogs.*.effective_predictive_optimization_flag.value catalog.EnablePredictiveOptimization REMOTE resources.catalogs.*.enable_predictive_optimization catalog.EnablePredictiveOptimization REMOTE resources.catalogs.*.full_name string REMOTE -resources.catalogs.*.grants []resources.CatalogGrant INPUT -resources.catalogs.*.grants[*] resources.CatalogGrant INPUT +resources.catalogs.*.grants []catalog.PrivilegeAssignment INPUT +resources.catalogs.*.grants[*] catalog.PrivilegeAssignment INPUT resources.catalogs.*.grants[*].principal string INPUT -resources.catalogs.*.grants[*].privileges []resources.CatalogGrantPrivilege INPUT -resources.catalogs.*.grants[*].privileges[*] resources.CatalogGrantPrivilege INPUT +resources.catalogs.*.grants[*].privileges []catalog.Privilege INPUT +resources.catalogs.*.grants[*].privileges[*] catalog.Privilege INPUT resources.catalogs.*.id string INPUT resources.catalogs.*.isolation_mode catalog.CatalogIsolationMode REMOTE resources.catalogs.*.lifecycle resources.Lifecycle INPUT @@ -261,8 +261,8 @@ resources.catalogs.*.updated_at int64 REMOTE resources.catalogs.*.updated_by string REMOTE resources.catalogs.*.url string INPUT resources.catalogs.*.grants.full_name string ALL -resources.catalogs.*.grants.grants []dresources.GrantAssignment ALL -resources.catalogs.*.grants.grants[*] dresources.GrantAssignment ALL +resources.catalogs.*.grants.grants []catalog.PrivilegeAssignment ALL +resources.catalogs.*.grants.grants[*] catalog.PrivilegeAssignment ALL resources.catalogs.*.grants.grants[*].principal string ALL resources.catalogs.*.grants.grants[*].privileges []catalog.Privilege ALL resources.catalogs.*.grants.grants[*].privileges[*] catalog.Privilege ALL @@ -710,11 +710,11 @@ resources.external_locations.*.file_event_queue.provided_pubsub.subscription_nam resources.external_locations.*.file_event_queue.provided_sqs *catalog.AwsSqsQueue ALL resources.external_locations.*.file_event_queue.provided_sqs.managed_resource_id string ALL resources.external_locations.*.file_event_queue.provided_sqs.queue_url string ALL -resources.external_locations.*.grants []resources.ExternalLocationGrant INPUT -resources.external_locations.*.grants[*] resources.ExternalLocationGrant INPUT +resources.external_locations.*.grants []catalog.PrivilegeAssignment INPUT +resources.external_locations.*.grants[*] catalog.PrivilegeAssignment INPUT resources.external_locations.*.grants[*].principal string INPUT -resources.external_locations.*.grants[*].privileges []resources.ExternalLocationGrantPrivilege INPUT -resources.external_locations.*.grants[*].privileges[*] resources.ExternalLocationGrantPrivilege INPUT +resources.external_locations.*.grants[*].privileges []catalog.Privilege INPUT +resources.external_locations.*.grants[*].privileges[*] catalog.Privilege INPUT resources.external_locations.*.id string INPUT resources.external_locations.*.isolation_mode catalog.IsolationMode REMOTE resources.external_locations.*.lifecycle resources.Lifecycle INPUT @@ -729,8 +729,8 @@ resources.external_locations.*.updated_at int64 REMOTE resources.external_locations.*.updated_by string REMOTE resources.external_locations.*.url string ALL resources.external_locations.*.grants.full_name string ALL -resources.external_locations.*.grants.grants []dresources.GrantAssignment ALL -resources.external_locations.*.grants.grants[*] dresources.GrantAssignment ALL +resources.external_locations.*.grants.grants []catalog.PrivilegeAssignment ALL +resources.external_locations.*.grants.grants[*] catalog.PrivilegeAssignment ALL resources.external_locations.*.grants.grants[*].principal string ALL resources.external_locations.*.grants.grants[*].privileges []catalog.Privilege ALL resources.external_locations.*.grants.grants[*].privileges[*] catalog.Privilege ALL @@ -2748,11 +2748,11 @@ resources.registered_models.*.comment string ALL resources.registered_models.*.created_at int64 ALL resources.registered_models.*.created_by string ALL resources.registered_models.*.full_name string ALL -resources.registered_models.*.grants []resources.Grant INPUT -resources.registered_models.*.grants[*] resources.Grant INPUT +resources.registered_models.*.grants []catalog.PrivilegeAssignment INPUT +resources.registered_models.*.grants[*] catalog.PrivilegeAssignment INPUT resources.registered_models.*.grants[*].principal string INPUT -resources.registered_models.*.grants[*].privileges []string INPUT -resources.registered_models.*.grants[*].privileges[*] string INPUT +resources.registered_models.*.grants[*].privileges []catalog.Privilege INPUT +resources.registered_models.*.grants[*].privileges[*] catalog.Privilege INPUT resources.registered_models.*.id string INPUT resources.registered_models.*.lifecycle resources.Lifecycle INPUT resources.registered_models.*.lifecycle.prevent_destroy bool INPUT @@ -2766,8 +2766,8 @@ resources.registered_models.*.updated_at int64 ALL resources.registered_models.*.updated_by string ALL resources.registered_models.*.url string INPUT resources.registered_models.*.grants.full_name string ALL -resources.registered_models.*.grants.grants []dresources.GrantAssignment ALL -resources.registered_models.*.grants.grants[*] dresources.GrantAssignment ALL +resources.registered_models.*.grants.grants []catalog.PrivilegeAssignment ALL +resources.registered_models.*.grants.grants[*] catalog.PrivilegeAssignment ALL resources.registered_models.*.grants.grants[*].principal string ALL resources.registered_models.*.grants.grants[*].privileges []catalog.Privilege ALL resources.registered_models.*.grants.grants[*].privileges[*] catalog.Privilege ALL @@ -2784,11 +2784,11 @@ resources.schemas.*.effective_predictive_optimization_flag.inherited_from_type c resources.schemas.*.effective_predictive_optimization_flag.value catalog.EnablePredictiveOptimization REMOTE resources.schemas.*.enable_predictive_optimization catalog.EnablePredictiveOptimization REMOTE resources.schemas.*.full_name string REMOTE -resources.schemas.*.grants []resources.SchemaGrant INPUT -resources.schemas.*.grants[*] resources.SchemaGrant INPUT +resources.schemas.*.grants []catalog.PrivilegeAssignment INPUT +resources.schemas.*.grants[*] catalog.PrivilegeAssignment INPUT resources.schemas.*.grants[*].principal string INPUT -resources.schemas.*.grants[*].privileges []resources.SchemaGrantPrivilege INPUT -resources.schemas.*.grants[*].privileges[*] resources.SchemaGrantPrivilege INPUT +resources.schemas.*.grants[*].privileges []catalog.Privilege INPUT +resources.schemas.*.grants[*].privileges[*] catalog.Privilege INPUT resources.schemas.*.id string INPUT resources.schemas.*.lifecycle resources.Lifecycle INPUT resources.schemas.*.lifecycle.prevent_destroy bool INPUT @@ -2805,8 +2805,8 @@ resources.schemas.*.updated_at int64 REMOTE resources.schemas.*.updated_by string REMOTE resources.schemas.*.url string INPUT resources.schemas.*.grants.full_name string ALL -resources.schemas.*.grants.grants []dresources.GrantAssignment ALL -resources.schemas.*.grants.grants[*] dresources.GrantAssignment ALL +resources.schemas.*.grants.grants []catalog.PrivilegeAssignment ALL +resources.schemas.*.grants.grants[*] catalog.PrivilegeAssignment ALL resources.schemas.*.grants.grants[*].principal string ALL resources.schemas.*.grants.grants[*].privileges []catalog.Privilege ALL resources.schemas.*.grants.grants[*].privileges[*] catalog.Privilege ALL @@ -2970,11 +2970,11 @@ resources.volumes.*.encryption_details.sse_encryption_details *catalog.SseEncryp resources.volumes.*.encryption_details.sse_encryption_details.algorithm catalog.SseEncryptionDetailsAlgorithm REMOTE resources.volumes.*.encryption_details.sse_encryption_details.aws_kms_key_arn string REMOTE resources.volumes.*.full_name string REMOTE -resources.volumes.*.grants []resources.VolumeGrant INPUT -resources.volumes.*.grants[*] resources.VolumeGrant INPUT +resources.volumes.*.grants []catalog.PrivilegeAssignment INPUT +resources.volumes.*.grants[*] catalog.PrivilegeAssignment INPUT resources.volumes.*.grants[*].principal string INPUT -resources.volumes.*.grants[*].privileges []resources.VolumeGrantPrivilege INPUT -resources.volumes.*.grants[*].privileges[*] resources.VolumeGrantPrivilege INPUT +resources.volumes.*.grants[*].privileges []catalog.Privilege INPUT +resources.volumes.*.grants[*].privileges[*] catalog.Privilege INPUT resources.volumes.*.id string INPUT resources.volumes.*.lifecycle resources.Lifecycle INPUT resources.volumes.*.lifecycle.prevent_destroy bool INPUT @@ -2990,8 +2990,8 @@ resources.volumes.*.url string INPUT resources.volumes.*.volume_id string REMOTE resources.volumes.*.volume_type catalog.VolumeType ALL resources.volumes.*.grants.full_name string ALL -resources.volumes.*.grants.grants []dresources.GrantAssignment ALL -resources.volumes.*.grants.grants[*] dresources.GrantAssignment ALL +resources.volumes.*.grants.grants []catalog.PrivilegeAssignment ALL +resources.volumes.*.grants.grants[*] catalog.PrivilegeAssignment ALL resources.volumes.*.grants.grants[*].principal string ALL resources.volumes.*.grants.grants[*].privileges []catalog.Privilege ALL resources.volumes.*.grants.grants[*].privileges[*] catalog.Privilege ALL From 2c9cc4f60be744e978972ece8b6b8f0664c718f6 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 5 Mar 2026 13:07:44 +0100 Subject: [PATCH 06/15] generate --- .../internal/schema/annotations_openapi.yml | 111 +++++++ .../validation/generated/enum_fields.go | 10 +- .../validation/generated/required_fields.go | 14 +- bundle/schema/jsonschema.json | 64 +++- bundle/schema/jsonschema_for_docs.json | 305 ++++++++---------- .../databricks/bundles/catalogs/__init__.py | 25 +- .../bundles/catalogs/_models/catalog.py | 12 +- .../bundles/catalogs/_models/catalog_grant.py | 40 --- .../_models/catalog_grant_privilege.py | 62 ---- .../bundles/catalogs/_models/privilege.py | 112 +++++++ .../catalogs/_models/privilege_assignment.py | 51 +++ python/databricks/bundles/schemas/__init__.py | 25 +- .../schemas/_models/privilege_assignment.py | 51 +++ .../bundles/schemas/_models/schema.py | 10 +- .../bundles/schemas/_models/schema_grant.py | 40 --- .../schemas/_models/schema_grant_privilege.py | 44 --- python/databricks/bundles/volumes/__init__.py | 25 +- .../bundles/volumes/_models/privilege.py | 112 +++++++ .../volumes/_models/privilege_assignment.py | 51 +++ .../bundles/volumes/_models/volume.py | 10 +- .../bundles/volumes/_models/volume_grant.py | 40 --- .../volumes/_models/volume_grant_privilege.py | 16 - 22 files changed, 741 insertions(+), 489 deletions(-) delete mode 100644 python/databricks/bundles/catalogs/_models/catalog_grant.py delete mode 100644 python/databricks/bundles/catalogs/_models/catalog_grant_privilege.py create mode 100644 python/databricks/bundles/catalogs/_models/privilege.py create mode 100644 python/databricks/bundles/catalogs/_models/privilege_assignment.py create mode 100644 python/databricks/bundles/schemas/_models/privilege_assignment.py delete mode 100644 python/databricks/bundles/schemas/_models/schema_grant.py delete mode 100644 python/databricks/bundles/schemas/_models/schema_grant_privilege.py create mode 100644 python/databricks/bundles/volumes/_models/privilege.py create mode 100644 python/databricks/bundles/volumes/_models/privilege_assignment.py delete mode 100644 python/databricks/bundles/volumes/_models/volume_grant.py delete mode 100644 python/databricks/bundles/volumes/_models/volume_grant_privilege.py diff --git a/bundle/internal/schema/annotations_openapi.yml b/bundle/internal/schema/annotations_openapi.yml index d033809ef5..882f5c1cf2 100644 --- a/bundle/internal/schema/annotations_openapi.yml +++ b/bundle/internal/schema/annotations_openapi.yml @@ -1688,6 +1688,117 @@ github.com/databricks/databricks-sdk-go/service/catalog.MonitorTimeSeries: "timestamp_col": "description": |- Column for the timestamp. +github.com/databricks/databricks-sdk-go/service/catalog.Privilege: + "_": + "enum": + - |- + 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 +github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment: + "principal": + "description": |- + The principal (user email address or group name). + For deleted principals, `principal` is empty while `principal_id` is populated. + "privileges": + "description": |- + The privileges assigned to the principal. github.com/databricks/databricks-sdk-go/service/catalog.RegisteredModelAlias: "alias_name": "description": |- diff --git a/bundle/internal/validation/generated/enum_fields.go b/bundle/internal/validation/generated/enum_fields.go index c1ea107de4..81b2fdb284 100644 --- a/bundle/internal/validation/generated/enum_fields.go +++ b/bundle/internal/validation/generated/enum_fields.go @@ -33,7 +33,7 @@ var EnumFields = map[string][]string{ "resources.apps.*.resources[*].uc_securable.permission": {"EXECUTE", "MODIFY", "READ_VOLUME", "SELECT", "USE_CONNECTION", "WRITE_VOLUME"}, "resources.apps.*.resources[*].uc_securable.securable_type": {"CONNECTION", "FUNCTION", "TABLE", "VOLUME"}, - "resources.catalogs.*.grants[*].privileges[*]": {"ALL_PRIVILEGES", "APPLY_TAG", "CREATE_CONNECTION", "CREATE_EXTERNAL_LOCATION", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_FOREIGN_CATALOG", "CREATE_FUNCTION", "CREATE_MANAGED_STORAGE", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_SCHEMA", "CREATE_STORAGE_CREDENTIAL", "CREATE_TABLE", "CREATE_VOLUME", "EXECUTE", "MANAGE", "MODIFY", "READ_VOLUME", "REFRESH", "SELECT", "USE_CATALOG", "USE_CONNECTION", "USE_SCHEMA", "WRITE_VOLUME"}, + "resources.catalogs.*.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_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.clusters.*.aws_attributes.availability": {"ON_DEMAND", "SPOT", "SPOT_WITH_FALLBACK"}, "resources.clusters.*.aws_attributes.ebs_volume_type": {"GENERAL_PURPOSE_SSD", "THROUGHPUT_OPTIMIZED_HDD"}, @@ -48,7 +48,7 @@ var EnumFields = map[string][]string{ "resources.database_instances.*.state": {"AVAILABLE", "DELETING", "FAILING_OVER", "STARTING", "STOPPED", "UPDATING"}, "resources.external_locations.*.encryption_details.sse_encryption_details.algorithm": {"AWS_SSE_KMS", "AWS_SSE_S3"}, - "resources.external_locations.*.grants[*].privileges[*]": {"ALL_PRIVILEGES", "CREATE_EXTERNAL_TABLE", "CREATE_EXTERNAL_VOLUME", "CREATE_MANAGED_STORAGE", "CREATE_TABLE", "CREATE_VOLUME", "MANAGE", "READ_FILES", "WRITE_FILES"}, + "resources.external_locations.*.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_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.jobs.*.continuous.pause_status": {"PAUSED", "UNPAUSED"}, "resources.jobs.*.continuous.task_retry_mode": {"NEVER", "ON_FAILURE"}, @@ -144,7 +144,9 @@ var EnumFields = map[string][]string{ "resources.quality_monitors.*.inference_log.problem_type": {"PROBLEM_TYPE_CLASSIFICATION", "PROBLEM_TYPE_REGRESSION"}, "resources.quality_monitors.*.schedule.pause_status": {"PAUSED", "UNPAUSED", "UNSPECIFIED"}, - "resources.schemas.*.grants[*].privileges[*]": {"ALL_PRIVILEGES", "APPLY_TAG", "CREATE_FUNCTION", "CREATE_MATERIALIZED_VIEW", "CREATE_MODEL", "CREATE_TABLE", "CREATE_VOLUME", "EXECUTE", "EXTERNAL_USE_SCHEMA", "MANAGE", "MODIFY", "READ_VOLUME", "REFRESH", "SELECT", "USE_SCHEMA", "WRITE_VOLUME"}, + "resources.registered_models.*.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_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.schemas.*.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_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.secret_scopes.*.backend_type": {"AZURE_KEYVAULT", "DATABRICKS"}, @@ -159,7 +161,7 @@ var EnumFields = map[string][]string{ "resources.synced_database_tables.*.spec.scheduling_policy": {"CONTINUOUS", "SNAPSHOT", "TRIGGERED"}, "resources.synced_database_tables.*.unity_catalog_provisioning_state": {"ACTIVE", "DEGRADED", "DELETING", "FAILED", "PROVISIONING", "UPDATING"}, - "resources.volumes.*.grants[*].privileges[*]": {"ALL_PRIVILEGES", "APPLY_TAG", "MANAGE", "READ_VOLUME", "WRITE_VOLUME"}, + "resources.volumes.*.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_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.volumes.*.volume_type": {"EXTERNAL", "MANAGED"}, "variables.*.type": {"complex"}, diff --git a/bundle/internal/validation/generated/required_fields.go b/bundle/internal/validation/generated/required_fields.go index 74679a659c..857caa2523 100644 --- a/bundle/internal/validation/generated/required_fields.go +++ b/bundle/internal/validation/generated/required_fields.go @@ -35,8 +35,7 @@ var RequiredFields = map[string][]string{ "resources.apps.*.resources[*].sql_warehouse": {"id", "permission"}, "resources.apps.*.resources[*].uc_securable": {"permission", "securable_full_name", "securable_type"}, - "resources.catalogs.*": {"name"}, - "resources.catalogs.*.grants[*]": {"privileges", "principal"}, + "resources.catalogs.*": {"name"}, "resources.clusters.*.cluster_log_conf.dbfs": {"destination"}, "resources.clusters.*.cluster_log_conf.s3": {"destination"}, @@ -61,8 +60,7 @@ var RequiredFields = map[string][]string{ "resources.experiments.*": {"name"}, "resources.experiments.*.permissions[*]": {"level"}, - "resources.external_locations.*": {"credential_name", "name", "url"}, - "resources.external_locations.*.grants[*]": {"privileges", "principal"}, + "resources.external_locations.*": {"credential_name", "name", "url"}, "resources.jobs.*.deployment": {"kind"}, "resources.jobs.*.environments[*]": {"environment_key"}, @@ -228,10 +226,7 @@ var RequiredFields = map[string][]string{ "resources.quality_monitors.*.schedule": {"quartz_cron_expression", "timezone_id"}, "resources.quality_monitors.*.time_series": {"granularities", "timestamp_col"}, - "resources.registered_models.*.grants[*]": {"privileges", "principal"}, - - "resources.schemas.*": {"catalog_name", "name"}, - "resources.schemas.*.grants[*]": {"privileges", "principal"}, + "resources.schemas.*": {"catalog_name", "name"}, "resources.secret_scopes.*": {"name"}, "resources.secret_scopes.*.keyvault_metadata": {"dns_name", "resource_id"}, @@ -241,8 +236,7 @@ var RequiredFields = map[string][]string{ "resources.synced_database_tables.*": {"name"}, - "resources.volumes.*": {"catalog_name", "name", "schema_name", "volume_type"}, - "resources.volumes.*.grants[*]": {"privileges", "principal"}, + "resources.volumes.*": {"catalog_name", "name", "schema_name", "volume_type"}, "scripts.*": {"content"}, } diff --git a/bundle/schema/jsonschema.json b/bundle/schema/jsonschema.json index e6d265bb20..4c78fa6683 100644 --- a/bundle/schema/jsonschema.json +++ b/bundle/schema/jsonschema.json @@ -4085,7 +4085,67 @@ ] }, "catalog.Privilege": { - "type": "string" + "oneOf": [ + { + "type": "string", + "enum": [ + "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" + ] + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] }, "catalog.PrivilegeAssignment": { "oneOf": [ @@ -4093,9 +4153,11 @@ "type": "object", "properties": { "principal": { + "description": "The principal (user email address or group name).\nFor deleted principals, `principal` is empty while `principal_id` is populated.", "$ref": "#/$defs/string" }, "privileges": { + "description": "The privileges assigned to the principal.", "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.Privilege" } }, diff --git a/bundle/schema/jsonschema_for_docs.json b/bundle/schema/jsonschema_for_docs.json index 52b8df408b..e4dd4584c3 100644 --- a/bundle/schema/jsonschema_for_docs.json +++ b/bundle/schema/jsonschema_for_docs.json @@ -144,11 +144,6 @@ "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/apps.GitSource", "x-since-version": "v0.290.0" }, - "lifecycle": { - "description": "Lifecycle is a struct that contains the lifecycle settings for a resource. It controls the behavior of the resource when it is deployed or destroyed.", - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle", - "x-since-version": "v0.268.0" - }, "name": { "description": "The name of the app. The name must contain only lowercase alphanumeric characters and hyphens.\nIt must be unique within the workspace.", "$ref": "#/$defs/string", @@ -178,6 +173,11 @@ "$ref": "#/$defs/string", "x-since-version": "v0.283.0" }, + "lifecycle": { + "description": "Lifecycle is a struct that contains the lifecycle settings for a resource. It controls the behavior of the resource when it is deployed or destroyed.", + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle", + "x-since-version": "v0.268.0" + }, "user_api_scopes": { "$ref": "#/$defs/slice/string", "x-since-version": "v0.246.0" @@ -267,7 +267,7 @@ "x-since-version": "v0.287.0" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.CatalogGrant", + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment", "x-since-version": "v0.287.0" }, "lifecycle": { @@ -304,24 +304,6 @@ "name" ] }, - "resources.CatalogGrant": { - "type": "object", - "properties": { - "principal": { - "$ref": "#/$defs/string", - "x-since-version": "v0.287.0" - }, - "privileges": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.CatalogGrantPrivilege", - "x-since-version": "v0.287.0" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, "resources.CatalogGrantPrivilege": { "type": "string", "enum": [ @@ -822,6 +804,7 @@ "CAN_MANAGE" ] }, +<<<<<<< HEAD "resources.DatabaseProjectPermission": { "type": "object", "properties": { @@ -847,13 +830,37 @@ "level" ] }, - "resources.DatabaseProjectPermissionLevel": { - "type": "string", - "enum": [ - "CAN_USE", - "CAN_MANAGE" +||||||| parent of 839ba969a (generate) +======= + "resources.DatabaseProjectPermission": { + "type": "object", + "properties": { + "group_name": { + "$ref": "#/$defs/string" + }, + "level": { + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.DatabaseProjectPermissionLevel" + }, + "service_principal_name": { + "$ref": "#/$defs/string" + }, + "user_name": { + "$ref": "#/$defs/string" + } + }, + "additionalProperties": false, + "required": [ + "level" ] }, +>>>>>>> 839ba969a (generate) + "resources.DatabaseProjectPermissionLevel": { + "type": "string", + "enum": [ + "CAN_USE", + "CAN_MANAGE" + ] + }, "resources.ExternalLocation": { "type": "object", "properties": { @@ -882,7 +889,7 @@ "x-since-version": "v0.289.0" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.ExternalLocationGrant", + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment", "x-since-version": "v0.289.0" }, "lifecycle": { @@ -913,24 +920,6 @@ "url" ] }, - "resources.ExternalLocationGrant": { - "type": "object", - "properties": { - "principal": { - "$ref": "#/$defs/string", - "x-since-version": "v0.289.0" - }, - "privileges": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.ExternalLocationGrantPrivilege", - "x-since-version": "v0.289.0" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, "resources.ExternalLocationGrantPrivilege": { "type": "string", "description": "Privilege to grant on an external location", @@ -946,26 +935,6 @@ "WRITE_FILES" ] }, - "resources.Grant": { - "type": "object", - "properties": { - "principal": { - "description": "The name of the principal that will be granted privileges", - "$ref": "#/$defs/string", - "x-since-version": "v0.229.0" - }, - "privileges": { - "description": "The privileges to grant to the specified entity", - "$ref": "#/$defs/slice/string", - "x-since-version": "v0.229.0" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, "resources.Job": { "type": "object", "properties": { @@ -1736,14 +1705,21 @@ "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle", "x-since-version": "v0.287.0" }, +<<<<<<< HEAD "permissions": { "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.DatabaseProjectPermission", "x-since-version": "v0.292.0" }, - "pg_version": { - "$ref": "#/$defs/int", - "x-since-version": "v0.287.0" +||||||| parent of 839ba969a (generate) +======= + "permissions": { + "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.DatabaseProjectPermission" }, +>>>>>>> 839ba969a (generate) + "pg_version": { + "$ref": "#/$defs/int", + "x-since-version": "v0.287.0" + }, "project_id": { "$ref": "#/$defs/string", "x-since-version": "v0.287.0" @@ -1880,7 +1856,7 @@ "x-since-version": "v0.273.0" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.Grant", + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment", "x-since-version": "v0.229.0" }, "lifecycle": { @@ -1937,7 +1913,7 @@ "x-since-version": "v0.229.0" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.SchemaGrant", + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment", "x-since-version": "v0.229.0" }, "lifecycle": { @@ -1967,24 +1943,6 @@ ], "markdownDescription": "The schema resource type allows you to define Unity Catalog [schemas](https://docs.databricks.com/api/workspace/schemas/create) for tables and other assets in your workflows and pipelines created as part of a bundle. A schema, different from other resource types, has the following limitations:\n\n- The owner of a schema resource is always the deployment user, and cannot be changed. If `run_as` is specified in the bundle, it will be ignored by operations on the schema.\n- Only fields supported by the corresponding [Schemas object create API](https://docs.databricks.com/api/workspace/schemas/create) are available for the schema resource. For example, `enable_predictive_optimization` is not supported as it is only available on the [update API](https://docs.databricks.com/api/workspace/schemas/update)." }, - "resources.SchemaGrant": { - "type": "object", - "properties": { - "principal": { - "$ref": "#/$defs/string", - "x-since-version": "v0.267.0" - }, - "privileges": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.SchemaGrantPrivilege", - "x-since-version": "v0.267.0" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, "resources.SchemaGrantPrivilege": { "type": "string", "enum": [ @@ -2236,7 +2194,7 @@ "x-since-version": "v0.236.0" }, "grants": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.VolumeGrant", + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment", "x-since-version": "v0.236.0" }, "lifecycle": { @@ -2272,34 +2230,6 @@ ], "markdownDescription": "The volume resource type allows you to define and create Unity Catalog [volumes](https://docs.databricks.com/api/workspace/volumes/create) as part of a bundle. When deploying a bundle with a volume defined, note that:\n\n- A volume cannot be referenced in the `artifact_path` for the bundle until it exists in the workspace. Hence, if you want to use Databricks Asset Bundles to create the volume, you must first define the volume in the bundle, deploy it to create the volume, then reference it in the `artifact_path` in subsequent deployments.\n\n- Volumes in the bundle are not prepended with the `dev_${workspace.current_user.short_name}` prefix when the deployment target has `mode: development` configured. However, you can manually configure this prefix. See [custom-presets](https://docs.databricks.com/dev-tools/bundles/deployment-modes.html#custom-presets)." }, - "resources.VolumeGrant": { - "type": "object", - "properties": { - "principal": { - "$ref": "#/$defs/string", - "x-since-version": "v0.264.1" - }, - "privileges": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.VolumeGrantPrivilege", - "x-since-version": "v0.264.1" - } - }, - "additionalProperties": false, - "required": [ - "privileges", - "principal" - ] - }, - "resources.VolumeGrantPrivilege": { - "type": "string", - "enum": [ - "ALL_PRIVILEGES", - "APPLY_TAG", - "MANAGE", - "READ_VOLUME", - "WRITE_VOLUME" - ] - }, "variable.Lookup": { "type": "object", "properties": { @@ -8886,6 +8816,75 @@ "resource_id" ] }, + "catalog.Privilege": { + "type": "string", + "enum": [ + "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" + ] + }, + "catalog.PrivilegeAssignment": { + "type": "object", + "properties": { + "principal": { + "description": "The principal (user email address or group name).\nFor deleted principals, `principal` is empty while `principal_id` is populated.", + "$ref": "#/$defs/string" + }, + "privileges": { + "description": "The privileges assigned to the principal.", + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.Privilege" + } + }, + "additionalProperties": false + }, "workspace.ScopeBackendType": { "type": "string", "description": "The types of secret scope backends in the Secret Manager. Azure KeyVault backed secret scopes\nwill be supported in a later release.", @@ -9121,18 +9120,6 @@ "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.AppPermission" } }, - "resources.CatalogGrant": { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.CatalogGrant" - } - }, - "resources.CatalogGrantPrivilege": { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.CatalogGrantPrivilege" - } - }, "resources.ClusterPermission": { "type": "array", "items": { @@ -9157,24 +9144,6 @@ "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.DatabaseProjectPermission" } }, - "resources.ExternalLocationGrant": { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.ExternalLocationGrant" - } - }, - "resources.ExternalLocationGrantPrivilege": { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.ExternalLocationGrantPrivilege" - } - }, - "resources.Grant": { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Grant" - } - }, "resources.JobPermission": { "type": "array", "items": { @@ -9211,18 +9180,6 @@ "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.PipelinePermission" } }, - "resources.SchemaGrant": { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.SchemaGrant" - } - }, - "resources.SchemaGrantPrivilege": { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.SchemaGrantPrivilege" - } - }, "resources.SecretScopePermission": { "type": "array", "items": { @@ -9234,18 +9191,6 @@ "items": { "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.SqlWarehousePermission" } - }, - "resources.VolumeGrant": { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.VolumeGrant" - } - }, - "resources.VolumeGrantPrivilege": { - "type": "array", - "items": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.VolumeGrantPrivilege" - } } }, "config.ArtifactFile": { @@ -9276,6 +9221,18 @@ "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/catalog.MonitorMetric" } }, + "catalog.Privilege": { + "type": "array", + "items": { + "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/catalog.Privilege" + } + }, + "catalog.PrivilegeAssignment": { + "type": "array", + "items": { + "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/catalog.PrivilegeAssignment" + } + }, "catalog.RegisteredModelAlias": { "type": "array", "items": { diff --git a/python/databricks/bundles/catalogs/__init__.py b/python/databricks/bundles/catalogs/__init__.py index b0b79f2dd5..fe323f3ef1 100644 --- a/python/databricks/bundles/catalogs/__init__.py +++ b/python/databricks/bundles/catalogs/__init__.py @@ -1,15 +1,15 @@ __all__ = [ "Catalog", "CatalogDict", - "CatalogGrant", - "CatalogGrantDict", - "CatalogGrantParam", - "CatalogGrantPrivilege", - "CatalogGrantPrivilegeParam", "CatalogParam", "Lifecycle", "LifecycleDict", "LifecycleParam", + "Privilege", + "PrivilegeAssignment", + "PrivilegeAssignmentDict", + "PrivilegeAssignmentParam", + "PrivilegeParam", ] @@ -18,17 +18,14 @@ CatalogDict, CatalogParam, ) -from databricks.bundles.catalogs._models.catalog_grant import ( - CatalogGrant, - CatalogGrantDict, - CatalogGrantParam, -) -from databricks.bundles.catalogs._models.catalog_grant_privilege import ( - CatalogGrantPrivilege, - CatalogGrantPrivilegeParam, -) from databricks.bundles.catalogs._models.lifecycle import ( Lifecycle, LifecycleDict, LifecycleParam, ) +from databricks.bundles.catalogs._models.privilege import Privilege, PrivilegeParam +from databricks.bundles.catalogs._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentDict, + PrivilegeAssignmentParam, +) diff --git a/python/databricks/bundles/catalogs/_models/catalog.py b/python/databricks/bundles/catalogs/_models/catalog.py index 9d59a29265..368e96a3b2 100644 --- a/python/databricks/bundles/catalogs/_models/catalog.py +++ b/python/databricks/bundles/catalogs/_models/catalog.py @@ -1,11 +1,11 @@ from dataclasses import dataclass, field from typing import TYPE_CHECKING, TypedDict -from databricks.bundles.catalogs._models.catalog_grant import ( - CatalogGrant, - CatalogGrantParam, -) from databricks.bundles.catalogs._models.lifecycle import Lifecycle, LifecycleParam +from databricks.bundles.catalogs._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentParam, +) 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 @@ -30,7 +30,7 @@ class Catalog(Resource): connection_name: VariableOrOptional[str] = None - grants: VariableOrList[CatalogGrant] = field(default_factory=list) + grants: VariableOrList[PrivilegeAssignment] = field(default_factory=list) lifecycle: VariableOrOptional[Lifecycle] = None @@ -61,7 +61,7 @@ class CatalogDict(TypedDict, total=False): connection_name: VariableOrOptional[str] - grants: VariableOrList[CatalogGrantParam] + grants: VariableOrList[PrivilegeAssignmentParam] lifecycle: VariableOrOptional[LifecycleParam] diff --git a/python/databricks/bundles/catalogs/_models/catalog_grant.py b/python/databricks/bundles/catalogs/_models/catalog_grant.py deleted file mode 100644 index 6c0ddebb5e..0000000000 --- a/python/databricks/bundles/catalogs/_models/catalog_grant.py +++ /dev/null @@ -1,40 +0,0 @@ -from dataclasses import dataclass, field -from typing import TYPE_CHECKING, TypedDict - -from databricks.bundles.catalogs._models.catalog_grant_privilege import ( - CatalogGrantPrivilege, - CatalogGrantPrivilegeParam, -) -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, VariableOrList - -if TYPE_CHECKING: - from typing_extensions import Self - - -@dataclass(kw_only=True) -class CatalogGrant: - """""" - - principal: VariableOr[str] - - privileges: VariableOrList[CatalogGrantPrivilege] = field(default_factory=list) - - @classmethod - def from_dict(cls, value: "CatalogGrantDict") -> "Self": - return _transform(cls, value) - - def as_dict(self) -> "CatalogGrantDict": - return _transform_to_json_value(self) # type:ignore - - -class CatalogGrantDict(TypedDict, total=False): - """""" - - principal: VariableOr[str] - - privileges: VariableOrList[CatalogGrantPrivilegeParam] - - -CatalogGrantParam = CatalogGrantDict | CatalogGrant diff --git a/python/databricks/bundles/catalogs/_models/catalog_grant_privilege.py b/python/databricks/bundles/catalogs/_models/catalog_grant_privilege.py deleted file mode 100644 index 97c433876f..0000000000 --- a/python/databricks/bundles/catalogs/_models/catalog_grant_privilege.py +++ /dev/null @@ -1,62 +0,0 @@ -from enum import Enum -from typing import Literal - - -class CatalogGrantPrivilege(Enum): - ALL_PRIVILEGES = "ALL_PRIVILEGES" - APPLY_TAG = "APPLY_TAG" - CREATE_CONNECTION = "CREATE_CONNECTION" - CREATE_EXTERNAL_LOCATION = "CREATE_EXTERNAL_LOCATION" - CREATE_EXTERNAL_TABLE = "CREATE_EXTERNAL_TABLE" - CREATE_EXTERNAL_VOLUME = "CREATE_EXTERNAL_VOLUME" - CREATE_FOREIGN_CATALOG = "CREATE_FOREIGN_CATALOG" - CREATE_FUNCTION = "CREATE_FUNCTION" - CREATE_MANAGED_STORAGE = "CREATE_MANAGED_STORAGE" - CREATE_MATERIALIZED_VIEW = "CREATE_MATERIALIZED_VIEW" - CREATE_MODEL = "CREATE_MODEL" - CREATE_SCHEMA = "CREATE_SCHEMA" - CREATE_STORAGE_CREDENTIAL = "CREATE_STORAGE_CREDENTIAL" - CREATE_TABLE = "CREATE_TABLE" - CREATE_VOLUME = "CREATE_VOLUME" - EXECUTE = "EXECUTE" - MANAGE = "MANAGE" - MODIFY = "MODIFY" - READ_VOLUME = "READ_VOLUME" - REFRESH = "REFRESH" - SELECT = "SELECT" - USE_CATALOG = "USE_CATALOG" - USE_CONNECTION = "USE_CONNECTION" - USE_SCHEMA = "USE_SCHEMA" - WRITE_VOLUME = "WRITE_VOLUME" - - -CatalogGrantPrivilegeParam = ( - Literal[ - "ALL_PRIVILEGES", - "APPLY_TAG", - "CREATE_CONNECTION", - "CREATE_EXTERNAL_LOCATION", - "CREATE_EXTERNAL_TABLE", - "CREATE_EXTERNAL_VOLUME", - "CREATE_FOREIGN_CATALOG", - "CREATE_FUNCTION", - "CREATE_MANAGED_STORAGE", - "CREATE_MATERIALIZED_VIEW", - "CREATE_MODEL", - "CREATE_SCHEMA", - "CREATE_STORAGE_CREDENTIAL", - "CREATE_TABLE", - "CREATE_VOLUME", - "EXECUTE", - "MANAGE", - "MODIFY", - "READ_VOLUME", - "REFRESH", - "SELECT", - "USE_CATALOG", - "USE_CONNECTION", - "USE_SCHEMA", - "WRITE_VOLUME", - ] - | CatalogGrantPrivilege -) diff --git a/python/databricks/bundles/catalogs/_models/privilege.py b/python/databricks/bundles/catalogs/_models/privilege.py new file mode 100644 index 0000000000..20f4e1f557 --- /dev/null +++ b/python/databricks/bundles/catalogs/_models/privilege.py @@ -0,0 +1,112 @@ +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" + + +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", + ] + | Privilege +) diff --git a/python/databricks/bundles/catalogs/_models/privilege_assignment.py b/python/databricks/bundles/catalogs/_models/privilege_assignment.py new file mode 100644 index 0000000000..f3b6755821 --- /dev/null +++ b/python/databricks/bundles/catalogs/_models/privilege_assignment.py @@ -0,0 +1,51 @@ +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, TypedDict + +from databricks.bundles.catalogs._models.privilege import Privilege, PrivilegeParam +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 + +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/schemas/__init__.py b/python/databricks/bundles/schemas/__init__.py index d4d0fa33a3..80e9f50bd6 100644 --- a/python/databricks/bundles/schemas/__init__.py +++ b/python/databricks/bundles/schemas/__init__.py @@ -2,13 +2,13 @@ "Lifecycle", "LifecycleDict", "LifecycleParam", + "Privilege", + "PrivilegeAssignment", + "PrivilegeAssignmentDict", + "PrivilegeAssignmentParam", + "PrivilegeParam", "Schema", "SchemaDict", - "SchemaGrant", - "SchemaGrantDict", - "SchemaGrantParam", - "SchemaGrantPrivilege", - "SchemaGrantPrivilegeParam", "SchemaParam", ] @@ -18,13 +18,10 @@ LifecycleDict, LifecycleParam, ) -from databricks.bundles.schemas._models.schema import Schema, SchemaDict, SchemaParam -from databricks.bundles.schemas._models.schema_grant import ( - SchemaGrant, - SchemaGrantDict, - SchemaGrantParam, -) -from databricks.bundles.schemas._models.schema_grant_privilege import ( - SchemaGrantPrivilege, - SchemaGrantPrivilegeParam, +from databricks.bundles.schemas._models.privilege import Privilege, PrivilegeParam +from databricks.bundles.schemas._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentDict, + PrivilegeAssignmentParam, ) +from databricks.bundles.schemas._models.schema import Schema, SchemaDict, SchemaParam diff --git a/python/databricks/bundles/schemas/_models/privilege_assignment.py b/python/databricks/bundles/schemas/_models/privilege_assignment.py new file mode 100644 index 0000000000..c60d5a82ec --- /dev/null +++ b/python/databricks/bundles/schemas/_models/privilege_assignment.py @@ -0,0 +1,51 @@ +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.schemas._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/schemas/_models/schema.py b/python/databricks/bundles/schemas/_models/schema.py index 58975f0474..d12385e395 100644 --- a/python/databricks/bundles/schemas/_models/schema.py +++ b/python/databricks/bundles/schemas/_models/schema.py @@ -11,9 +11,9 @@ VariableOrOptional, ) from databricks.bundles.schemas._models.lifecycle import Lifecycle, LifecycleParam -from databricks.bundles.schemas._models.schema_grant import ( - SchemaGrant, - SchemaGrantParam, +from databricks.bundles.schemas._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentParam, ) if TYPE_CHECKING: @@ -39,7 +39,7 @@ class Schema(Resource): User-provided free-form text description. """ - grants: VariableOrList[SchemaGrant] = field(default_factory=list) + grants: VariableOrList[PrivilegeAssignment] = field(default_factory=list) lifecycle: VariableOrOptional[Lifecycle] = None """ @@ -79,7 +79,7 @@ class SchemaDict(TypedDict, total=False): User-provided free-form text description. """ - grants: VariableOrList[SchemaGrantParam] + grants: VariableOrList[PrivilegeAssignmentParam] lifecycle: VariableOrOptional[LifecycleParam] """ diff --git a/python/databricks/bundles/schemas/_models/schema_grant.py b/python/databricks/bundles/schemas/_models/schema_grant.py deleted file mode 100644 index 4997db89c6..0000000000 --- a/python/databricks/bundles/schemas/_models/schema_grant.py +++ /dev/null @@ -1,40 +0,0 @@ -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 VariableOr, VariableOrList -from databricks.bundles.schemas._models.schema_grant_privilege import ( - SchemaGrantPrivilege, - SchemaGrantPrivilegeParam, -) - -if TYPE_CHECKING: - from typing_extensions import Self - - -@dataclass(kw_only=True) -class SchemaGrant: - """""" - - principal: VariableOr[str] - - privileges: VariableOrList[SchemaGrantPrivilege] = field(default_factory=list) - - @classmethod - def from_dict(cls, value: "SchemaGrantDict") -> "Self": - return _transform(cls, value) - - def as_dict(self) -> "SchemaGrantDict": - return _transform_to_json_value(self) # type:ignore - - -class SchemaGrantDict(TypedDict, total=False): - """""" - - principal: VariableOr[str] - - privileges: VariableOrList[SchemaGrantPrivilegeParam] - - -SchemaGrantParam = SchemaGrantDict | SchemaGrant diff --git a/python/databricks/bundles/schemas/_models/schema_grant_privilege.py b/python/databricks/bundles/schemas/_models/schema_grant_privilege.py deleted file mode 100644 index be00afa961..0000000000 --- a/python/databricks/bundles/schemas/_models/schema_grant_privilege.py +++ /dev/null @@ -1,44 +0,0 @@ -from enum import Enum -from typing import Literal - - -class SchemaGrantPrivilege(Enum): - ALL_PRIVILEGES = "ALL_PRIVILEGES" - APPLY_TAG = "APPLY_TAG" - CREATE_FUNCTION = "CREATE_FUNCTION" - CREATE_MATERIALIZED_VIEW = "CREATE_MATERIALIZED_VIEW" - CREATE_MODEL = "CREATE_MODEL" - CREATE_TABLE = "CREATE_TABLE" - CREATE_VOLUME = "CREATE_VOLUME" - EXECUTE = "EXECUTE" - EXTERNAL_USE_SCHEMA = "EXTERNAL_USE_SCHEMA" - MANAGE = "MANAGE" - MODIFY = "MODIFY" - READ_VOLUME = "READ_VOLUME" - REFRESH = "REFRESH" - SELECT = "SELECT" - USE_SCHEMA = "USE_SCHEMA" - WRITE_VOLUME = "WRITE_VOLUME" - - -SchemaGrantPrivilegeParam = ( - Literal[ - "ALL_PRIVILEGES", - "APPLY_TAG", - "CREATE_FUNCTION", - "CREATE_MATERIALIZED_VIEW", - "CREATE_MODEL", - "CREATE_TABLE", - "CREATE_VOLUME", - "EXECUTE", - "EXTERNAL_USE_SCHEMA", - "MANAGE", - "MODIFY", - "READ_VOLUME", - "REFRESH", - "SELECT", - "USE_SCHEMA", - "WRITE_VOLUME", - ] - | SchemaGrantPrivilege -) diff --git a/python/databricks/bundles/volumes/__init__.py b/python/databricks/bundles/volumes/__init__.py index 065713bf6c..609f5644c2 100644 --- a/python/databricks/bundles/volumes/__init__.py +++ b/python/databricks/bundles/volumes/__init__.py @@ -2,13 +2,13 @@ "Lifecycle", "LifecycleDict", "LifecycleParam", + "Privilege", + "PrivilegeAssignment", + "PrivilegeAssignmentDict", + "PrivilegeAssignmentParam", + "PrivilegeParam", "Volume", "VolumeDict", - "VolumeGrant", - "VolumeGrantDict", - "VolumeGrantParam", - "VolumeGrantPrivilege", - "VolumeGrantPrivilegeParam", "VolumeParam", "VolumeType", "VolumeTypeParam", @@ -20,14 +20,11 @@ LifecycleDict, LifecycleParam, ) -from databricks.bundles.volumes._models.volume import Volume, VolumeDict, VolumeParam -from databricks.bundles.volumes._models.volume_grant import ( - VolumeGrant, - VolumeGrantDict, - VolumeGrantParam, -) -from databricks.bundles.volumes._models.volume_grant_privilege import ( - VolumeGrantPrivilege, - VolumeGrantPrivilegeParam, +from databricks.bundles.volumes._models.privilege import Privilege, PrivilegeParam +from databricks.bundles.volumes._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentDict, + PrivilegeAssignmentParam, ) +from databricks.bundles.volumes._models.volume import Volume, VolumeDict, VolumeParam from databricks.bundles.volumes._models.volume_type import VolumeType, VolumeTypeParam diff --git a/python/databricks/bundles/volumes/_models/privilege.py b/python/databricks/bundles/volumes/_models/privilege.py new file mode 100644 index 0000000000..20f4e1f557 --- /dev/null +++ b/python/databricks/bundles/volumes/_models/privilege.py @@ -0,0 +1,112 @@ +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" + + +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", + ] + | Privilege +) diff --git a/python/databricks/bundles/volumes/_models/privilege_assignment.py b/python/databricks/bundles/volumes/_models/privilege_assignment.py new file mode 100644 index 0000000000..35b695e10d --- /dev/null +++ b/python/databricks/bundles/volumes/_models/privilege_assignment.py @@ -0,0 +1,51 @@ +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.volumes._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/volumes/_models/volume.py b/python/databricks/bundles/volumes/_models/volume.py index 20132cca96..bf77c831d6 100644 --- a/python/databricks/bundles/volumes/_models/volume.py +++ b/python/databricks/bundles/volumes/_models/volume.py @@ -10,9 +10,9 @@ VariableOrOptional, ) from databricks.bundles.volumes._models.lifecycle import Lifecycle, LifecycleParam -from databricks.bundles.volumes._models.volume_grant import ( - VolumeGrant, - VolumeGrantParam, +from databricks.bundles.volumes._models.privilege_assignment import ( + PrivilegeAssignment, + PrivilegeAssignmentParam, ) from databricks.bundles.volumes._models.volume_type import VolumeType, VolumeTypeParam @@ -44,7 +44,7 @@ class Volume(Resource): The comment attached to the volume """ - grants: VariableOrList[VolumeGrant] = field(default_factory=list) + grants: VariableOrList[PrivilegeAssignment] = field(default_factory=list) lifecycle: VariableOrOptional[Lifecycle] = None """ @@ -89,7 +89,7 @@ class VolumeDict(TypedDict, total=False): The comment attached to the volume """ - grants: VariableOrList[VolumeGrantParam] + grants: VariableOrList[PrivilegeAssignmentParam] lifecycle: VariableOrOptional[LifecycleParam] """ diff --git a/python/databricks/bundles/volumes/_models/volume_grant.py b/python/databricks/bundles/volumes/_models/volume_grant.py deleted file mode 100644 index 3bd580371e..0000000000 --- a/python/databricks/bundles/volumes/_models/volume_grant.py +++ /dev/null @@ -1,40 +0,0 @@ -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 VariableOr, VariableOrList -from databricks.bundles.volumes._models.volume_grant_privilege import ( - VolumeGrantPrivilege, - VolumeGrantPrivilegeParam, -) - -if TYPE_CHECKING: - from typing_extensions import Self - - -@dataclass(kw_only=True) -class VolumeGrant: - """""" - - principal: VariableOr[str] - - privileges: VariableOrList[VolumeGrantPrivilege] = field(default_factory=list) - - @classmethod - def from_dict(cls, value: "VolumeGrantDict") -> "Self": - return _transform(cls, value) - - def as_dict(self) -> "VolumeGrantDict": - return _transform_to_json_value(self) # type:ignore - - -class VolumeGrantDict(TypedDict, total=False): - """""" - - principal: VariableOr[str] - - privileges: VariableOrList[VolumeGrantPrivilegeParam] - - -VolumeGrantParam = VolumeGrantDict | VolumeGrant diff --git a/python/databricks/bundles/volumes/_models/volume_grant_privilege.py b/python/databricks/bundles/volumes/_models/volume_grant_privilege.py deleted file mode 100644 index d758ca6d82..0000000000 --- a/python/databricks/bundles/volumes/_models/volume_grant_privilege.py +++ /dev/null @@ -1,16 +0,0 @@ -from enum import Enum -from typing import Literal - - -class VolumeGrantPrivilege(Enum): - ALL_PRIVILEGES = "ALL_PRIVILEGES" - APPLY_TAG = "APPLY_TAG" - MANAGE = "MANAGE" - READ_VOLUME = "READ_VOLUME" - WRITE_VOLUME = "WRITE_VOLUME" - - -VolumeGrantPrivilegeParam = ( - Literal["ALL_PRIVILEGES", "APPLY_TAG", "MANAGE", "READ_VOLUME", "WRITE_VOLUME"] - | VolumeGrantPrivilege -) From f6b9f2ba78d66dc593513aee7fb0cc74c34b7d3c Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 5 Mar 2026 14:25:33 +0100 Subject: [PATCH 07/15] fix __init__py --- python/databricks/bundles/schemas/__init__.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/databricks/bundles/schemas/__init__.py b/python/databricks/bundles/schemas/__init__.py index 80e9f50bd6..b2e70dc937 100644 --- a/python/databricks/bundles/schemas/__init__.py +++ b/python/databricks/bundles/schemas/__init__.py @@ -2,11 +2,9 @@ "Lifecycle", "LifecycleDict", "LifecycleParam", - "Privilege", "PrivilegeAssignment", "PrivilegeAssignmentDict", "PrivilegeAssignmentParam", - "PrivilegeParam", "Schema", "SchemaDict", "SchemaParam", @@ -18,7 +16,6 @@ LifecycleDict, LifecycleParam, ) -from databricks.bundles.schemas._models.privilege import Privilege, PrivilegeParam from databricks.bundles.schemas._models.privilege_assignment import ( PrivilegeAssignment, PrivilegeAssignmentDict, From eaf3797c9be4b7405185d366f20b276a13c4bb92 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 5 Mar 2026 14:41:22 +0100 Subject: [PATCH 08/15] add missing databricks/bundles/schemas/_models/privilege.py --- .../bundles/schemas/_models/privilege.py | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 python/databricks/bundles/schemas/_models/privilege.py diff --git a/python/databricks/bundles/schemas/_models/privilege.py b/python/databricks/bundles/schemas/_models/privilege.py new file mode 100644 index 0000000000..20f4e1f557 --- /dev/null +++ b/python/databricks/bundles/schemas/_models/privilege.py @@ -0,0 +1,112 @@ +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" + + +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", + ] + | Privilege +) From 45c5cd49119a0aa6c80c80c0a651c269d3f4b65e Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Thu, 5 Mar 2026 17:42:48 +0100 Subject: [PATCH 09/15] update --- bundle/schema/jsonschema_for_docs.json | 262 ++++++------------ python/databricks/bundles/schemas/__init__.py | 3 + 2 files changed, 85 insertions(+), 180 deletions(-) diff --git a/bundle/schema/jsonschema_for_docs.json b/bundle/schema/jsonschema_for_docs.json index e4dd4584c3..8856a74c85 100644 --- a/bundle/schema/jsonschema_for_docs.json +++ b/bundle/schema/jsonschema_for_docs.json @@ -144,6 +144,11 @@ "$ref": "#/$defs/github.com/databricks/databricks-sdk-go/service/apps.GitSource", "x-since-version": "v0.290.0" }, + "lifecycle": { + "description": "Lifecycle is a struct that contains the lifecycle settings for a resource. It controls the behavior of the resource when it is deployed or destroyed.", + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle", + "x-since-version": "v0.268.0" + }, "name": { "description": "The name of the app. The name must contain only lowercase alphanumeric characters and hyphens.\nIt must be unique within the workspace.", "$ref": "#/$defs/string", @@ -173,11 +178,6 @@ "$ref": "#/$defs/string", "x-since-version": "v0.283.0" }, - "lifecycle": { - "description": "Lifecycle is a struct that contains the lifecycle settings for a resource. It controls the behavior of the resource when it is deployed or destroyed.", - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle", - "x-since-version": "v0.268.0" - }, "user_api_scopes": { "$ref": "#/$defs/slice/string", "x-since-version": "v0.246.0" @@ -304,36 +304,6 @@ "name" ] }, - "resources.CatalogGrantPrivilege": { - "type": "string", - "enum": [ - "ALL_PRIVILEGES", - "APPLY_TAG", - "CREATE_CONNECTION", - "CREATE_EXTERNAL_LOCATION", - "CREATE_EXTERNAL_TABLE", - "CREATE_EXTERNAL_VOLUME", - "CREATE_FOREIGN_CATALOG", - "CREATE_FUNCTION", - "CREATE_MANAGED_STORAGE", - "CREATE_MATERIALIZED_VIEW", - "CREATE_MODEL", - "CREATE_SCHEMA", - "CREATE_STORAGE_CREDENTIAL", - "CREATE_TABLE", - "CREATE_VOLUME", - "EXECUTE", - "MANAGE", - "MODIFY", - "READ_VOLUME", - "REFRESH", - "SELECT", - "USE_CATALOG", - "USE_CONNECTION", - "USE_SCHEMA", - "WRITE_VOLUME" - ] - }, "resources.Cluster": { "type": "object", "description": "Contains a snapshot of the latest user specified settings that were used to create/edit the cluster.", @@ -804,7 +774,6 @@ "CAN_MANAGE" ] }, -<<<<<<< HEAD "resources.DatabaseProjectPermission": { "type": "object", "properties": { @@ -830,37 +799,13 @@ "level" ] }, -||||||| parent of 839ba969a (generate) -======= - "resources.DatabaseProjectPermission": { - "type": "object", - "properties": { - "group_name": { - "$ref": "#/$defs/string" - }, - "level": { - "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.DatabaseProjectPermissionLevel" - }, - "service_principal_name": { - "$ref": "#/$defs/string" - }, - "user_name": { - "$ref": "#/$defs/string" - } - }, - "additionalProperties": false, - "required": [ - "level" + "resources.DatabaseProjectPermissionLevel": { + "type": "string", + "enum": [ + "CAN_USE", + "CAN_MANAGE" ] }, ->>>>>>> 839ba969a (generate) - "resources.DatabaseProjectPermissionLevel": { - "type": "string", - "enum": [ - "CAN_USE", - "CAN_MANAGE" - ] - }, "resources.ExternalLocation": { "type": "object", "properties": { @@ -920,21 +865,6 @@ "url" ] }, - "resources.ExternalLocationGrantPrivilege": { - "type": "string", - "description": "Privilege to grant on an external location", - "enum": [ - "ALL_PRIVILEGES", - "CREATE_EXTERNAL_TABLE", - "CREATE_EXTERNAL_VOLUME", - "CREATE_MANAGED_STORAGE", - "CREATE_TABLE", - "CREATE_VOLUME", - "MANAGE", - "READ_FILES", - "WRITE_FILES" - ] - }, "resources.Job": { "type": "object", "properties": { @@ -1705,21 +1635,14 @@ "$ref": "#/$defs/github.com/databricks/cli/bundle/config/resources.Lifecycle", "x-since-version": "v0.287.0" }, -<<<<<<< HEAD "permissions": { "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.DatabaseProjectPermission", "x-since-version": "v0.292.0" }, -||||||| parent of 839ba969a (generate) -======= - "permissions": { - "$ref": "#/$defs/slice/github.com/databricks/cli/bundle/config/resources.DatabaseProjectPermission" - }, ->>>>>>> 839ba969a (generate) "pg_version": { - "$ref": "#/$defs/int", - "x-since-version": "v0.287.0" - }, + "$ref": "#/$defs/int", + "x-since-version": "v0.287.0" + }, "project_id": { "$ref": "#/$defs/string", "x-since-version": "v0.287.0" @@ -1943,27 +1866,6 @@ ], "markdownDescription": "The schema resource type allows you to define Unity Catalog [schemas](https://docs.databricks.com/api/workspace/schemas/create) for tables and other assets in your workflows and pipelines created as part of a bundle. A schema, different from other resource types, has the following limitations:\n\n- The owner of a schema resource is always the deployment user, and cannot be changed. If `run_as` is specified in the bundle, it will be ignored by operations on the schema.\n- Only fields supported by the corresponding [Schemas object create API](https://docs.databricks.com/api/workspace/schemas/create) are available for the schema resource. For example, `enable_predictive_optimization` is not supported as it is only available on the [update API](https://docs.databricks.com/api/workspace/schemas/update)." }, - "resources.SchemaGrantPrivilege": { - "type": "string", - "enum": [ - "ALL_PRIVILEGES", - "APPLY_TAG", - "CREATE_FUNCTION", - "CREATE_MATERIALIZED_VIEW", - "CREATE_MODEL", - "CREATE_TABLE", - "CREATE_VOLUME", - "EXECUTE", - "EXTERNAL_USE_SCHEMA", - "MANAGE", - "MODIFY", - "READ_VOLUME", - "REFRESH", - "SELECT", - "USE_SCHEMA", - "WRITE_VOLUME" - ] - }, "resources.SecretScope": { "type": "object", "properties": { @@ -3740,6 +3642,75 @@ "timestamp_col" ] }, + "catalog.Privilege": { + "type": "string", + "enum": [ + "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" + ] + }, + "catalog.PrivilegeAssignment": { + "type": "object", + "properties": { + "principal": { + "description": "The principal (user email address or group name).\nFor deleted principals, `principal` is empty while `principal_id` is populated.", + "$ref": "#/$defs/string" + }, + "privileges": { + "description": "The privileges assigned to the principal.", + "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.Privilege" + } + }, + "additionalProperties": false + }, "catalog.RegisteredModelAlias": { "type": "object", "properties": { @@ -8816,75 +8787,6 @@ "resource_id" ] }, - "catalog.Privilege": { - "type": "string", - "enum": [ - "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" - ] - }, - "catalog.PrivilegeAssignment": { - "type": "object", - "properties": { - "principal": { - "description": "The principal (user email address or group name).\nFor deleted principals, `principal` is empty while `principal_id` is populated.", - "$ref": "#/$defs/string" - }, - "privileges": { - "description": "The privileges assigned to the principal.", - "$ref": "#/$defs/slice/github.com/databricks/databricks-sdk-go/service/catalog.Privilege" - } - }, - "additionalProperties": false - }, "workspace.ScopeBackendType": { "type": "string", "description": "The types of secret scope backends in the Secret Manager. Azure KeyVault backed secret scopes\nwill be supported in a later release.", diff --git a/python/databricks/bundles/schemas/__init__.py b/python/databricks/bundles/schemas/__init__.py index b2e70dc937..80e9f50bd6 100644 --- a/python/databricks/bundles/schemas/__init__.py +++ b/python/databricks/bundles/schemas/__init__.py @@ -2,9 +2,11 @@ "Lifecycle", "LifecycleDict", "LifecycleParam", + "Privilege", "PrivilegeAssignment", "PrivilegeAssignmentDict", "PrivilegeAssignmentParam", + "PrivilegeParam", "Schema", "SchemaDict", "SchemaParam", @@ -16,6 +18,7 @@ LifecycleDict, LifecycleParam, ) +from databricks.bundles.schemas._models.privilege import Privilege, PrivilegeParam from databricks.bundles.schemas._models.privilege_assignment import ( PrivilegeAssignment, PrivilegeAssignmentDict, From 091b5385fa3bb38a568fa4f0206e6f5c716843a3 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Fri, 6 Mar 2026 10:21:09 +0100 Subject: [PATCH 10/15] Fix schema testdata: replace INSERT with MODIFY in registered_model grants INSERT is not a valid Unity Catalog privilege. After switching from the custom Grant type (which used []string for privileges) to catalog.PrivilegeAssignment from the SDK, the privileges field is now enum-validated. MODIFY is the appropriate UC privilege for write operations. Co-Authored-By: Claude Sonnet 4.6 --- bundle/internal/schema/testdata/pass/ml.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundle/internal/schema/testdata/pass/ml.yml b/bundle/internal/schema/testdata/pass/ml.yml index 3c0c39a0d2..d2885b6412 100644 --- a/bundle/internal/schema/testdata/pass/ml.yml +++ b/bundle/internal/schema/testdata/pass/ml.yml @@ -65,4 +65,4 @@ resources: - principal: abcd privileges: - SELECT - - INSERT + - MODIFY From a3ade89cc05eaccf623788f9e50cb537ee28d5c7 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Fri, 6 Mar 2026 12:10:51 +0100 Subject: [PATCH 11/15] python: add backward compat aliases for renamed grant types CatalogGrant/SchemaGrant/VolumeGrant and their privilege enums were replaced by the unified PrivilegeAssignment/Privilege types. Add aliases in each namespace's __init__.py so existing code continues to work without changes. The generator now reads codegen/aliases_patch.py and emits OldName = NewName assignments into each namespace's __init__.py, including the old names in __all__. Co-Authored-By: Claude Sonnet 4.6 --- python/codegen/ALIASES_ANALYSIS.md | 64 +++++++++++ python/codegen/codegen/aliases_patch.py | 25 ++++ python/codegen/codegen/main.py | 10 ++ .../databricks/bundles/catalogs/__init__.py | 11 ++ python/databricks/bundles/schemas/__init__.py | 11 ++ python/databricks/bundles/volumes/__init__.py | 11 ++ .../databricks_tests/bundles/test_aliases.py | 108 ++++++++++++++++++ 7 files changed, 240 insertions(+) create mode 100644 python/codegen/ALIASES_ANALYSIS.md create mode 100644 python/codegen/codegen/aliases_patch.py create mode 100644 python/databricks_tests/bundles/test_aliases.py diff --git a/python/codegen/ALIASES_ANALYSIS.md b/python/codegen/ALIASES_ANALYSIS.md new file mode 100644 index 0000000000..5d1b0dd03a --- /dev/null +++ b/python/codegen/ALIASES_ANALYSIS.md @@ -0,0 +1,64 @@ +# Python Codegen: Backward Compatibility Aliases Analysis + +## Context + +The `Privilege` and `PrivilegeAssignment` types are duplicated across three namespaces +(`catalogs`, `schemas`, `volumes`) by design — each namespace is self-contained with no +cross-namespace imports, avoiding coupling issues from Databricks SDK v1. + +Before this change, each namespace had resource-specific grant types: +- `catalogs`: `CatalogGrant`, `CatalogGrantPrivilege` +- `schemas`: `SchemaGrant`, `SchemaGrantPrivilege` +- `volumes`: `VolumeGrant`, `VolumeGrantPrivilege` + +These were replaced by the shared (but duplicated) `PrivilegeAssignment` and `Privilege`. + +## Alias Mapping + +| namespace | old name | new name | +|---|---|---| +| catalogs | `CatalogGrant` | `PrivilegeAssignment` | +| catalogs | `CatalogGrantDict` | `PrivilegeAssignmentDict` | +| catalogs | `CatalogGrantParam` | `PrivilegeAssignmentParam` | +| catalogs | `CatalogGrantPrivilege` | `Privilege` | +| catalogs | `CatalogGrantPrivilegeParam` | `PrivilegeParam` | +| schemas | `SchemaGrant` | `PrivilegeAssignment` | +| schemas | `SchemaGrantDict` | `PrivilegeAssignmentDict` | +| schemas | `SchemaGrantParam` | `PrivilegeAssignmentParam` | +| schemas | `SchemaGrantPrivilege` | `Privilege` | +| schemas | `SchemaGrantPrivilegeParam` | `PrivilegeParam` | +| volumes | `VolumeGrant` | `PrivilegeAssignment` | +| volumes | `VolumeGrantDict` | `PrivilegeAssignmentDict` | +| volumes | `VolumeGrantParam` | `PrivilegeAssignmentParam` | +| volumes | `VolumeGrantPrivilege` | `Privilege` | +| volumes | `VolumeGrantPrivilegeParam` | `PrivilegeParam` | + +## Options Considered + +### Option A: Append aliases to `__init__.py` only (CHOSEN) + +Modify `_write_exports()` to read an `ALIASES` dict and emit `OldName = NewName` +assignments after imports, plus add old names to `__all__`. + +- Pros: minimal change, no new files, fits existing pattern +- Cons: only `from databricks.bundles.catalogs import CatalogGrant` works, + not deep `_models`-level imports +- Sufficient for all realistic use cases + +### Option B: Generate a separate `_models/aliases.py` per namespace + +Produces a separate file with imports + alias assignments. + +- Pros: supports both package-level and `_models`-level imports +- Cons: more files, more generator complexity + +### Option C: Append aliases to the target model file + +Appends `CatalogGrant = PrivilegeAssignment` to `privilege_assignment.py`. + +- Cons: pollutes generated model files with namespace-specific legacy names + +## Implementation (Option A) + +1. New file: `codegen/aliases_patch.py` — defines `ALIASES: dict[str, dict[str, str]]` +2. `main.py` `_write_exports()` — append alias assignments and include old names in `__all__` diff --git a/python/codegen/codegen/aliases_patch.py b/python/codegen/codegen/aliases_patch.py new file mode 100644 index 0000000000..864f70afb9 --- /dev/null +++ b/python/codegen/codegen/aliases_patch.py @@ -0,0 +1,25 @@ +# Backward compatibility aliases: maps old generated type names to new names, per namespace. +# These are emitted into each namespace's __init__.py as simple assignments. +ALIASES: dict[str, dict[str, str]] = { + "catalogs": { + "CatalogGrant": "PrivilegeAssignment", + "CatalogGrantDict": "PrivilegeAssignmentDict", + "CatalogGrantParam": "PrivilegeAssignmentParam", + "CatalogGrantPrivilege": "Privilege", + "CatalogGrantPrivilegeParam": "PrivilegeParam", + }, + "schemas": { + "SchemaGrant": "PrivilegeAssignment", + "SchemaGrantDict": "PrivilegeAssignmentDict", + "SchemaGrantParam": "PrivilegeAssignmentParam", + "SchemaGrantPrivilege": "Privilege", + "SchemaGrantPrivilegeParam": "PrivilegeParam", + }, + "volumes": { + "VolumeGrant": "PrivilegeAssignment", + "VolumeGrantDict": "PrivilegeAssignmentDict", + "VolumeGrantParam": "PrivilegeAssignmentParam", + "VolumeGrantPrivilege": "Privilege", + "VolumeGrantPrivilegeParam": "PrivilegeParam", + }, +} diff --git a/python/codegen/codegen/main.py b/python/codegen/codegen/main.py index df26810338..d8764775c5 100644 --- a/python/codegen/codegen/main.py +++ b/python/codegen/codegen/main.py @@ -3,6 +3,7 @@ from pathlib import Path from textwrap import dedent +import codegen.aliases_patch as aliases_patch import codegen.generated_dataclass as generated_dataclass import codegen.generated_dataclass_patch as generated_dataclass_patch import codegen.generated_enum as generated_enum @@ -141,6 +142,8 @@ def _write_exports( for _, enum in enums.items(): exports += [enum.class_name, f"{enum.class_name}Param"] + aliases = aliases_patch.ALIASES.get(namespace, {}) + exports.sort() b = CodeBuilder() @@ -148,6 +151,8 @@ def _write_exports( b.append("__all__ = [\n") for export in exports: b.indent().append_repr(export).append(",").newline() + for old_name in sorted(aliases): + b.indent().append_repr(old_name).append(",").newline() b.append("]").newline() b.newline() b.newline() @@ -159,6 +164,11 @@ def _write_exports( if namespace == "jobs": _append_resolve_recursive_imports(b) + if aliases: + b.newline() + for old_name, new_name in sorted(aliases.items()): + b.append(f"{old_name} = {new_name}").newline() + root_package = packages.get_root_package(namespace) package_path = Path(root_package.replace(".", "/")) diff --git a/python/databricks/bundles/catalogs/__init__.py b/python/databricks/bundles/catalogs/__init__.py index fe323f3ef1..fc92f42e22 100644 --- a/python/databricks/bundles/catalogs/__init__.py +++ b/python/databricks/bundles/catalogs/__init__.py @@ -1,6 +1,11 @@ __all__ = [ "Catalog", "CatalogDict", + "CatalogGrant", + "CatalogGrantDict", + "CatalogGrantParam", + "CatalogGrantPrivilege", + "CatalogGrantPrivilegeParam", "CatalogParam", "Lifecycle", "LifecycleDict", @@ -29,3 +34,9 @@ PrivilegeAssignmentDict, PrivilegeAssignmentParam, ) + +CatalogGrant = PrivilegeAssignment +CatalogGrantDict = PrivilegeAssignmentDict +CatalogGrantParam = PrivilegeAssignmentParam +CatalogGrantPrivilege = Privilege +CatalogGrantPrivilegeParam = PrivilegeParam diff --git a/python/databricks/bundles/schemas/__init__.py b/python/databricks/bundles/schemas/__init__.py index 80e9f50bd6..11517faaab 100644 --- a/python/databricks/bundles/schemas/__init__.py +++ b/python/databricks/bundles/schemas/__init__.py @@ -9,6 +9,11 @@ "PrivilegeParam", "Schema", "SchemaDict", + "SchemaGrant", + "SchemaGrantDict", + "SchemaGrantParam", + "SchemaGrantPrivilege", + "SchemaGrantPrivilegeParam", "SchemaParam", ] @@ -25,3 +30,9 @@ PrivilegeAssignmentParam, ) from databricks.bundles.schemas._models.schema import Schema, SchemaDict, SchemaParam + +SchemaGrant = PrivilegeAssignment +SchemaGrantDict = PrivilegeAssignmentDict +SchemaGrantParam = PrivilegeAssignmentParam +SchemaGrantPrivilege = Privilege +SchemaGrantPrivilegeParam = PrivilegeParam diff --git a/python/databricks/bundles/volumes/__init__.py b/python/databricks/bundles/volumes/__init__.py index 609f5644c2..57cf0f1e90 100644 --- a/python/databricks/bundles/volumes/__init__.py +++ b/python/databricks/bundles/volumes/__init__.py @@ -9,6 +9,11 @@ "PrivilegeParam", "Volume", "VolumeDict", + "VolumeGrant", + "VolumeGrantDict", + "VolumeGrantParam", + "VolumeGrantPrivilege", + "VolumeGrantPrivilegeParam", "VolumeParam", "VolumeType", "VolumeTypeParam", @@ -28,3 +33,9 @@ ) from databricks.bundles.volumes._models.volume import Volume, VolumeDict, VolumeParam from databricks.bundles.volumes._models.volume_type import VolumeType, VolumeTypeParam + +VolumeGrant = PrivilegeAssignment +VolumeGrantDict = PrivilegeAssignmentDict +VolumeGrantParam = PrivilegeAssignmentParam +VolumeGrantPrivilege = Privilege +VolumeGrantPrivilegeParam = PrivilegeParam diff --git a/python/databricks_tests/bundles/test_aliases.py b/python/databricks_tests/bundles/test_aliases.py new file mode 100644 index 0000000000..f2cfbb2449 --- /dev/null +++ b/python/databricks_tests/bundles/test_aliases.py @@ -0,0 +1,108 @@ +""" +Backward compatibility: old per-resource grant types must remain importable as aliases +to the unified PrivilegeAssignment / Privilege types. +""" + +from databricks.bundles.catalogs import ( + CatalogGrant, + CatalogGrantDict, + CatalogGrantParam, + CatalogGrantPrivilege, + CatalogGrantPrivilegeParam, + Privilege, + PrivilegeAssignment, + PrivilegeParam, +) +from databricks.bundles.schemas import ( + Privilege as SchemaPrivilege, +) +from databricks.bundles.schemas import ( + PrivilegeAssignment as SchemaPrivilegeAssignment, +) +from databricks.bundles.schemas import ( + SchemaGrant, + SchemaGrantDict, + SchemaGrantParam, + SchemaGrantPrivilege, + SchemaGrantPrivilegeParam, +) +from databricks.bundles.volumes import ( + Privilege as VolumePrivilege, +) +from databricks.bundles.volumes import ( + PrivilegeAssignment as VolumePrivilegeAssignment, +) +from databricks.bundles.volumes import ( + VolumeGrant, + VolumeGrantDict, + VolumeGrantParam, + VolumeGrantPrivilege, + VolumeGrantPrivilegeParam, +) + + +def test_catalog_grant_aliases(): + assert CatalogGrant is PrivilegeAssignment + assert CatalogGrantPrivilege is Privilege + # Param types are union aliases; verify they resolve without error + assert CatalogGrantDict is not None + assert CatalogGrantParam is not None + assert CatalogGrantPrivilegeParam is PrivilegeParam + + +def test_schema_grant_aliases(): + assert SchemaGrant is SchemaPrivilegeAssignment + assert SchemaGrantPrivilege is SchemaPrivilege + assert SchemaGrantDict is not None + assert SchemaGrantParam is not None + assert SchemaGrantPrivilegeParam is not None + + +def test_volume_grant_aliases(): + assert VolumeGrant is VolumePrivilegeAssignment + assert VolumeGrantPrivilege is VolumePrivilege + assert VolumeGrantDict is not None + assert VolumeGrantParam is not None + assert VolumeGrantPrivilegeParam is not None + + +def test_catalog_grant_is_usable(): + g = CatalogGrant( + principal="user@example.com", privileges=[CatalogGrantPrivilege.SELECT] + ) + assert g.principal == "user@example.com" + assert g.privileges == [Privilege.SELECT] + + +def test_schema_grant_is_usable(): + g = SchemaGrant(principal="group", privileges=[SchemaGrantPrivilege.USE_SCHEMA]) + assert g.principal == "group" + assert g.privileges == [SchemaPrivilege.USE_SCHEMA] + + +def test_volume_grant_is_usable(): + g = VolumeGrant(principal="svc", privileges=[VolumeGrantPrivilege.READ_VOLUME]) + assert g.principal == "svc" + assert g.privileges == [VolumePrivilege.READ_VOLUME] + + +def test_catalog_grant_dict_roundtrip(): + grant: CatalogGrantDict = { + "principal": "user@example.com", + "privileges": ["SELECT"], + } + obj = CatalogGrant.from_dict(grant) + assert obj.principal == "user@example.com" + assert obj.privileges == [Privilege.SELECT] + + +def test_schema_grant_dict_roundtrip(): + grant: SchemaGrantDict = {"principal": "group", "privileges": ["USE_SCHEMA"]} + obj = SchemaGrant.from_dict(grant) + assert obj.privileges == [SchemaPrivilege.USE_SCHEMA] + + +def test_volume_grant_dict_roundtrip(): + grant: VolumeGrantDict = {"principal": "svc", "privileges": ["READ_VOLUME"]} + obj = VolumeGrant.from_dict(grant) + assert obj.privileges == [VolumePrivilege.READ_VOLUME] From a7fe168cddc65896aeeaf5b1a3f4daa3cf37a2a8 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Fri, 6 Mar 2026 12:16:40 +0100 Subject: [PATCH 12/15] acceptance: add grants-aliases test for backward compat Python types Validates that old per-resource grant aliases (SchemaGrant, SchemaGrantPrivilege) and new unified types (PrivilegeAssignment, Privilege) both work in bundle validate, producing identical output. Co-Authored-By: Claude Sonnet 4.6 --- .../python/grants-aliases/databricks.yml | 9 ++++ .../python/grants-aliases/out.test.toml | 6 +++ .../bundle/python/grants-aliases/output.txt | 39 +++++++++++++++++ .../bundle/python/grants-aliases/resources.py | 43 +++++++++++++++++++ .../bundle/python/grants-aliases/script | 6 +++ .../bundle/python/grants-aliases/test.toml | 7 +++ 6 files changed, 110 insertions(+) create mode 100644 acceptance/bundle/python/grants-aliases/databricks.yml create mode 100644 acceptance/bundle/python/grants-aliases/out.test.toml create mode 100644 acceptance/bundle/python/grants-aliases/output.txt create mode 100644 acceptance/bundle/python/grants-aliases/resources.py create mode 100644 acceptance/bundle/python/grants-aliases/script create mode 100644 acceptance/bundle/python/grants-aliases/test.toml diff --git a/acceptance/bundle/python/grants-aliases/databricks.yml b/acceptance/bundle/python/grants-aliases/databricks.yml new file mode 100644 index 0000000000..5cf3921b62 --- /dev/null +++ b/acceptance/bundle/python/grants-aliases/databricks.yml @@ -0,0 +1,9 @@ +bundle: + name: my_project + +sync: {paths: []} # don't need to copy files + +experimental: + python: + resources: + - "resources:load_resources" diff --git a/acceptance/bundle/python/grants-aliases/out.test.toml b/acceptance/bundle/python/grants-aliases/out.test.toml new file mode 100644 index 0000000000..0f245f65d5 --- /dev/null +++ b/acceptance/bundle/python/grants-aliases/out.test.toml @@ -0,0 +1,6 @@ +Local = true +Cloud = false + +[EnvMatrix] + DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] + UV_ARGS = ["--with-requirements requirements-latest.txt --no-cache"] diff --git a/acceptance/bundle/python/grants-aliases/output.txt b/acceptance/bundle/python/grants-aliases/output.txt new file mode 100644 index 0000000000..06c25f7832 --- /dev/null +++ b/acceptance/bundle/python/grants-aliases/output.txt @@ -0,0 +1,39 @@ + +>>> uv run --with-requirements requirements-latest.txt --no-cache -q [CLI] bundle validate --output json +{ + "experimental": { + "python": { + "resources": [ + "resources:load_resources" + ] + } + }, + "resources": { + "schemas": { + "my_schema": { + "catalog_name": "my_catalog", + "grants": [ + { + "principal": "data-team@example.com", + "privileges": [ + "USE_SCHEMA" + ] + } + ], + "name": "my_schema" + }, + "my_schema_legacy": { + "catalog_name": "my_catalog", + "grants": [ + { + "principal": "data-team@example.com", + "privileges": [ + "USE_SCHEMA" + ] + } + ], + "name": "my_schema_legacy" + } + } + } +} diff --git a/acceptance/bundle/python/grants-aliases/resources.py b/acceptance/bundle/python/grants-aliases/resources.py new file mode 100644 index 0000000000..deb53d964e --- /dev/null +++ b/acceptance/bundle/python/grants-aliases/resources.py @@ -0,0 +1,43 @@ +from databricks.bundles.core import Resources + +# New unified types (preferred going forward) +from databricks.bundles.schemas import Privilege, PrivilegeAssignment + +# Old per-resource aliases (kept for backward compatibility) +from databricks.bundles.schemas import SchemaGrant, SchemaGrantPrivilege + + +def load_resources() -> Resources: + resources = Resources() + + resources.add_schema( + "my_schema", + { + "name": "my_schema", + "catalog_name": "my_catalog", + # New type + "grants": [ + PrivilegeAssignment( + principal="data-team@example.com", + privileges=[Privilege.USE_SCHEMA], + ) + ], + }, + ) + + resources.add_schema( + "my_schema_legacy", + { + "name": "my_schema_legacy", + "catalog_name": "my_catalog", + # Old alias type — identical to PrivilegeAssignment at runtime + "grants": [ + SchemaGrant( + principal="data-team@example.com", + privileges=[SchemaGrantPrivilege.USE_SCHEMA], + ) + ], + }, + ) + + return resources diff --git a/acceptance/bundle/python/grants-aliases/script b/acceptance/bundle/python/grants-aliases/script new file mode 100644 index 0000000000..c94fd42a0c --- /dev/null +++ b/acceptance/bundle/python/grants-aliases/script @@ -0,0 +1,6 @@ +echo "$DATABRICKS_BUNDLES_WHEEL" > "requirements-latest.txt" + +trace uv run $UV_ARGS -q $CLI bundle validate --output json | \ + jq "pick(.experimental.python, .resources)" + +rm -fr .databricks __pycache__ diff --git a/acceptance/bundle/python/grants-aliases/test.toml b/acceptance/bundle/python/grants-aliases/test.toml new file mode 100644 index 0000000000..81f3b9e2d7 --- /dev/null +++ b/acceptance/bundle/python/grants-aliases/test.toml @@ -0,0 +1,7 @@ +Local = true +Cloud = false # tests don't interact with APIs + +[EnvMatrix] +UV_ARGS = [ + "--with-requirements requirements-latest.txt --no-cache", +] From 2f4a72e0728e55fc3c57748b674974f79688c3e6 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Fri, 6 Mar 2026 12:17:05 +0100 Subject: [PATCH 13/15] remove ALIASES_ANALYSIS.md Co-Authored-By: Claude Sonnet 4.6 --- python/codegen/ALIASES_ANALYSIS.md | 64 ------------------------------ 1 file changed, 64 deletions(-) delete mode 100644 python/codegen/ALIASES_ANALYSIS.md diff --git a/python/codegen/ALIASES_ANALYSIS.md b/python/codegen/ALIASES_ANALYSIS.md deleted file mode 100644 index 5d1b0dd03a..0000000000 --- a/python/codegen/ALIASES_ANALYSIS.md +++ /dev/null @@ -1,64 +0,0 @@ -# Python Codegen: Backward Compatibility Aliases Analysis - -## Context - -The `Privilege` and `PrivilegeAssignment` types are duplicated across three namespaces -(`catalogs`, `schemas`, `volumes`) by design — each namespace is self-contained with no -cross-namespace imports, avoiding coupling issues from Databricks SDK v1. - -Before this change, each namespace had resource-specific grant types: -- `catalogs`: `CatalogGrant`, `CatalogGrantPrivilege` -- `schemas`: `SchemaGrant`, `SchemaGrantPrivilege` -- `volumes`: `VolumeGrant`, `VolumeGrantPrivilege` - -These were replaced by the shared (but duplicated) `PrivilegeAssignment` and `Privilege`. - -## Alias Mapping - -| namespace | old name | new name | -|---|---|---| -| catalogs | `CatalogGrant` | `PrivilegeAssignment` | -| catalogs | `CatalogGrantDict` | `PrivilegeAssignmentDict` | -| catalogs | `CatalogGrantParam` | `PrivilegeAssignmentParam` | -| catalogs | `CatalogGrantPrivilege` | `Privilege` | -| catalogs | `CatalogGrantPrivilegeParam` | `PrivilegeParam` | -| schemas | `SchemaGrant` | `PrivilegeAssignment` | -| schemas | `SchemaGrantDict` | `PrivilegeAssignmentDict` | -| schemas | `SchemaGrantParam` | `PrivilegeAssignmentParam` | -| schemas | `SchemaGrantPrivilege` | `Privilege` | -| schemas | `SchemaGrantPrivilegeParam` | `PrivilegeParam` | -| volumes | `VolumeGrant` | `PrivilegeAssignment` | -| volumes | `VolumeGrantDict` | `PrivilegeAssignmentDict` | -| volumes | `VolumeGrantParam` | `PrivilegeAssignmentParam` | -| volumes | `VolumeGrantPrivilege` | `Privilege` | -| volumes | `VolumeGrantPrivilegeParam` | `PrivilegeParam` | - -## Options Considered - -### Option A: Append aliases to `__init__.py` only (CHOSEN) - -Modify `_write_exports()` to read an `ALIASES` dict and emit `OldName = NewName` -assignments after imports, plus add old names to `__all__`. - -- Pros: minimal change, no new files, fits existing pattern -- Cons: only `from databricks.bundles.catalogs import CatalogGrant` works, - not deep `_models`-level imports -- Sufficient for all realistic use cases - -### Option B: Generate a separate `_models/aliases.py` per namespace - -Produces a separate file with imports + alias assignments. - -- Pros: supports both package-level and `_models`-level imports -- Cons: more files, more generator complexity - -### Option C: Append aliases to the target model file - -Appends `CatalogGrant = PrivilegeAssignment` to `privilege_assignment.py`. - -- Cons: pollutes generated model files with namespace-specific legacy names - -## Implementation (Option A) - -1. New file: `codegen/aliases_patch.py` — defines `ALIASES: dict[str, dict[str, str]]` -2. `main.py` `_write_exports()` — append alias assignments and include old names in `__all__` From 721255faa9d509e393266e4f701b117c59dc00b3 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Fri, 6 Mar 2026 12:18:38 +0100 Subject: [PATCH 14/15] rm test_aliases.py --- .../databricks_tests/bundles/test_aliases.py | 108 ------------------ 1 file changed, 108 deletions(-) delete mode 100644 python/databricks_tests/bundles/test_aliases.py diff --git a/python/databricks_tests/bundles/test_aliases.py b/python/databricks_tests/bundles/test_aliases.py deleted file mode 100644 index f2cfbb2449..0000000000 --- a/python/databricks_tests/bundles/test_aliases.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -Backward compatibility: old per-resource grant types must remain importable as aliases -to the unified PrivilegeAssignment / Privilege types. -""" - -from databricks.bundles.catalogs import ( - CatalogGrant, - CatalogGrantDict, - CatalogGrantParam, - CatalogGrantPrivilege, - CatalogGrantPrivilegeParam, - Privilege, - PrivilegeAssignment, - PrivilegeParam, -) -from databricks.bundles.schemas import ( - Privilege as SchemaPrivilege, -) -from databricks.bundles.schemas import ( - PrivilegeAssignment as SchemaPrivilegeAssignment, -) -from databricks.bundles.schemas import ( - SchemaGrant, - SchemaGrantDict, - SchemaGrantParam, - SchemaGrantPrivilege, - SchemaGrantPrivilegeParam, -) -from databricks.bundles.volumes import ( - Privilege as VolumePrivilege, -) -from databricks.bundles.volumes import ( - PrivilegeAssignment as VolumePrivilegeAssignment, -) -from databricks.bundles.volumes import ( - VolumeGrant, - VolumeGrantDict, - VolumeGrantParam, - VolumeGrantPrivilege, - VolumeGrantPrivilegeParam, -) - - -def test_catalog_grant_aliases(): - assert CatalogGrant is PrivilegeAssignment - assert CatalogGrantPrivilege is Privilege - # Param types are union aliases; verify they resolve without error - assert CatalogGrantDict is not None - assert CatalogGrantParam is not None - assert CatalogGrantPrivilegeParam is PrivilegeParam - - -def test_schema_grant_aliases(): - assert SchemaGrant is SchemaPrivilegeAssignment - assert SchemaGrantPrivilege is SchemaPrivilege - assert SchemaGrantDict is not None - assert SchemaGrantParam is not None - assert SchemaGrantPrivilegeParam is not None - - -def test_volume_grant_aliases(): - assert VolumeGrant is VolumePrivilegeAssignment - assert VolumeGrantPrivilege is VolumePrivilege - assert VolumeGrantDict is not None - assert VolumeGrantParam is not None - assert VolumeGrantPrivilegeParam is not None - - -def test_catalog_grant_is_usable(): - g = CatalogGrant( - principal="user@example.com", privileges=[CatalogGrantPrivilege.SELECT] - ) - assert g.principal == "user@example.com" - assert g.privileges == [Privilege.SELECT] - - -def test_schema_grant_is_usable(): - g = SchemaGrant(principal="group", privileges=[SchemaGrantPrivilege.USE_SCHEMA]) - assert g.principal == "group" - assert g.privileges == [SchemaPrivilege.USE_SCHEMA] - - -def test_volume_grant_is_usable(): - g = VolumeGrant(principal="svc", privileges=[VolumeGrantPrivilege.READ_VOLUME]) - assert g.principal == "svc" - assert g.privileges == [VolumePrivilege.READ_VOLUME] - - -def test_catalog_grant_dict_roundtrip(): - grant: CatalogGrantDict = { - "principal": "user@example.com", - "privileges": ["SELECT"], - } - obj = CatalogGrant.from_dict(grant) - assert obj.principal == "user@example.com" - assert obj.privileges == [Privilege.SELECT] - - -def test_schema_grant_dict_roundtrip(): - grant: SchemaGrantDict = {"principal": "group", "privileges": ["USE_SCHEMA"]} - obj = SchemaGrant.from_dict(grant) - assert obj.privileges == [SchemaPrivilege.USE_SCHEMA] - - -def test_volume_grant_dict_roundtrip(): - grant: VolumeGrantDict = {"principal": "svc", "privileges": ["READ_VOLUME"]} - obj = VolumeGrant.from_dict(grant) - assert obj.privileges == [VolumePrivilege.READ_VOLUME] From 8653aba99e335bb030497e167505d67566964fb1 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Fri, 6 Mar 2026 13:14:48 +0100 Subject: [PATCH 15/15] update next changelog --- NEXT_CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 60149ed865..f0c17ef7c5 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -5,6 +5,7 @@ ### CLI ### Bundles +* Modify grants to use SDK types ([#4666](https://github.com/databricks/cli/pull/4666)) ### Dependency updates