@@ -2,10 +2,14 @@ package resources
22
33import (
44 "context"
5+ "fmt"
6+ "sort"
57 "testing"
68
79 "github.com/databricks/databricks-sdk-go/apierr"
810 "github.com/databricks/databricks-sdk-go/experimental/mocks"
11+ "github.com/databricks/databricks-sdk-go/service/catalog"
12+ "github.com/stretchr/testify/assert"
913 "github.com/stretchr/testify/mock"
1014 "github.com/stretchr/testify/require"
1115)
@@ -24,3 +28,141 @@ func TestSchemaNotFound(t *testing.T) {
2428 require .Falsef (t , exists , "Exists should return false when getting a 404 response from Workspace" )
2529 require .NoErrorf (t , err , "Exists should not return an error when getting a 404 response from Workspace" )
2630}
31+
32+ func TestSchemaGrantPrivilegesExhaustive (t * testing.T ) {
33+ // Privileges that are NOT valid for schemas and should be skipped.
34+ // These are valid for other securable types (catalogs, connections, etc.)
35+ // Source: https://docs.databricks.com/en/data-governance/unity-catalog/manage-privileges/privileges.html
36+ skippedPrivileges := map [catalog.Privilege ]string {
37+ // Catalog-level privileges
38+ catalog .PrivilegeCreateCatalog : "catalog-level" ,
39+ catalog .PrivilegeCreateSchema : "catalog-level" ,
40+ catalog .PrivilegeUseCatalog : "catalog-level" ,
41+
42+ // Connection-level privileges
43+ catalog .PrivilegeCreateConnection : "connection-level" ,
44+ catalog .PrivilegeUseConnection : "connection-level" ,
45+
46+ // Storage-level privileges
47+ catalog .PrivilegeCreateExternalLocation : "storage-level" ,
48+ catalog .PrivilegeCreateExternalTable : "storage-level" ,
49+ catalog .PrivilegeCreateExternalVolume : "storage-level" ,
50+ catalog .PrivilegeCreateManagedStorage : "storage-level" ,
51+ catalog .PrivilegeCreateStorageCredential : "storage-level" ,
52+ catalog .PrivilegeReadFiles : "storage-level" ,
53+ catalog .PrivilegeReadPrivateFiles : "storage-level" ,
54+ catalog .PrivilegeWriteFiles : "storage-level" ,
55+ catalog .PrivilegeWritePrivateFiles : "storage-level" ,
56+
57+ // Metastore-level privileges
58+ catalog .PrivilegeCreateProvider : "metastore-level" ,
59+ catalog .PrivilegeCreateRecipient : "metastore-level" ,
60+ catalog .PrivilegeCreateShare : "metastore-level" ,
61+ catalog .PrivilegeManageAllowlist : "metastore-level" ,
62+ catalog .PrivilegeUseProvider : "metastore-level" ,
63+ catalog .PrivilegeUseRecipient : "metastore-level" ,
64+ catalog .PrivilegeUseMarketplaceAssets : "metastore-level" ,
65+ catalog .PrivilegeCreateServiceCredential : "metastore-level" ,
66+
67+ // Share-level privileges
68+ catalog .PrivilegeSetSharePermission : "share-level" ,
69+ catalog .PrivilegeUseShare : "share-level" ,
70+
71+ // Clean room-level privileges
72+ catalog .PrivilegeCreateCleanRoom : "clean-room-level" ,
73+ catalog .PrivilegeExecuteCleanRoomTask : "clean-room-level" ,
74+ catalog .PrivilegeModifyCleanRoom : "clean-room-level" ,
75+
76+ // Foreign securable privileges
77+ catalog .PrivilegeCreateForeignCatalog : "foreign-securable" ,
78+ catalog .PrivilegeCreateForeignSecurable : "foreign-securable" ,
79+
80+ // Table/view-level privileges (not directly grantable on schema)
81+ catalog .PrivilegeCreateView : "table-level" ,
82+
83+ // Generic privileges that don't apply to schemas
84+ catalog .PrivilegeAccess : "generic" ,
85+ catalog .PrivilegeBrowse : "generic" ,
86+ catalog .PrivilegeCreate : "generic" ,
87+ catalog .PrivilegeUsage : "generic" ,
88+ }
89+
90+ // Get all SDK privileges dynamically
91+ var p catalog.Privilege
92+ sdkPrivileges := p .Values ()
93+
94+ // Get all privileges defined in our SchemaGrantPrivilege enum
95+ definedPrivileges := SchemaGrantPrivilege ("" ).Values ()
96+ definedPrivilegeMap := make (map [catalog.Privilege ]bool )
97+ for _ , priv := range definedPrivileges {
98+ definedPrivilegeMap [catalog .Privilege (priv )] = true
99+ }
100+
101+ // Build list of missing and unexpected privileges
102+ var missingPrivileges []catalog.Privilege
103+ var unexpectedPrivileges []catalog.Privilege
104+
105+ // Check each SDK privilege
106+ for _ , sdkPriv := range sdkPrivileges {
107+ isInDefined := definedPrivilegeMap [sdkPriv ]
108+ isInSkipList := skippedPrivileges [sdkPriv ] != ""
109+
110+ if ! isInDefined && ! isInSkipList {
111+ // SDK has a privilege that we neither defined nor explicitly skipped
112+ missingPrivileges = append (missingPrivileges , sdkPriv )
113+ }
114+
115+ if isInDefined && isInSkipList {
116+ // We defined a privilege that's in the skip list (contradiction)
117+ unexpectedPrivileges = append (unexpectedPrivileges , sdkPriv )
118+ }
119+ }
120+
121+ // Check for privileges we defined that don't exist in SDK
122+ sdkPrivilegeMap := make (map [catalog.Privilege ]bool )
123+ for _ , priv := range sdkPrivileges {
124+ sdkPrivilegeMap [priv ] = true
125+ }
126+
127+ var invalidPrivileges []SchemaGrantPrivilege
128+ for _ , definedPriv := range definedPrivileges {
129+ if ! sdkPrivilegeMap [catalog .Privilege (definedPriv )] {
130+ invalidPrivileges = append (invalidPrivileges , definedPriv )
131+ }
132+ }
133+
134+ // Report errors
135+ if len (missingPrivileges ) > 0 {
136+ sort .Slice (missingPrivileges , func (i , j int ) bool {
137+ return missingPrivileges [i ] < missingPrivileges [j ]
138+ })
139+ assert .Fail (t , fmt .Sprintf (
140+ "Found %d SDK privilege(s) that are not in SchemaGrantPrivilege and not in skip list.\n " +
141+ "If these privileges are valid for schemas, add them to SchemaGrantPrivilege in schema.go.\n " +
142+ "If they are NOT valid for schemas, add them to skippedPrivileges in schema_test.go.\n " +
143+ "Missing privileges: %v" ,
144+ len (missingPrivileges ), missingPrivileges ))
145+ }
146+
147+ if len (unexpectedPrivileges ) > 0 {
148+ sort .Slice (unexpectedPrivileges , func (i , j int ) bool {
149+ return unexpectedPrivileges [i ] < unexpectedPrivileges [j ]
150+ })
151+ assert .Fail (t , fmt .Sprintf (
152+ "Found %d privilege(s) that are both defined in SchemaGrantPrivilege AND in skip list.\n " +
153+ "This is a contradiction - remove them from either SchemaGrantPrivilege or the skip list.\n " +
154+ "Conflicting privileges: %v" ,
155+ len (unexpectedPrivileges ), unexpectedPrivileges ))
156+ }
157+
158+ if len (invalidPrivileges ) > 0 {
159+ sort .Slice (invalidPrivileges , func (i , j int ) bool {
160+ return invalidPrivileges [i ] < invalidPrivileges [j ]
161+ })
162+ assert .Fail (t , fmt .Sprintf (
163+ "Found %d privilege(s) in SchemaGrantPrivilege that don't exist in the SDK.\n " +
164+ "Remove these from SchemaGrantPrivilege in schema.go.\n " +
165+ "Invalid privileges: %v" ,
166+ len (invalidPrivileges ), invalidPrivileges ))
167+ }
168+ }
0 commit comments