-
Notifications
You must be signed in to change notification settings - Fork 161
Expand file tree
/
Copy pathworkspace_path_permissions.go
More file actions
118 lines (103 loc) · 3.86 KB
/
workspace_path_permissions.go
File metadata and controls
118 lines (103 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package permissions
import (
"fmt"
"strings"
"github.com/databricks/cli/bundle/config/resources"
"github.com/databricks/cli/libs/diag"
"github.com/databricks/databricks-sdk-go/service/iam"
"github.com/databricks/databricks-sdk-go/service/workspace"
)
type WorkspacePathPermissions struct {
Path string
Permissions []resources.Permission
}
func ObjectAclToResourcePermissions(path string, acl []workspace.WorkspaceObjectAccessControlResponse, currentUser string) *WorkspacePathPermissions {
var permissions []resources.Permission
for _, a := range acl {
// Skip the admin group because it's added to all resources by default.
if a.GroupName == "admins" {
continue
}
// Skip the deploying identity because Databricks automatically grants it CAN_MANAGE.
if currentUser != "" && (a.UserName == currentUser || a.ServicePrincipalName == currentUser) {
continue
}
// Find the highest permission level for this principal (handles inherited + explicit permissions)
var highestLevel iam.PermissionLevel
for _, pl := range a.AllPermissions {
level := iam.PermissionLevel(convertWorkspaceObjectPermissionLevel(pl.PermissionLevel))
if resources.GetLevelScore(string(level)) > resources.GetLevelScore(string(highestLevel)) {
highestLevel = level
}
}
if highestLevel != "" {
permissions = append(permissions, resources.Permission{
Level: highestLevel,
GroupName: a.GroupName,
UserName: a.UserName,
ServicePrincipalName: a.ServicePrincipalName,
})
}
}
return &WorkspacePathPermissions{Permissions: permissions, Path: path}
}
func (p WorkspacePathPermissions) Compare(perms []resources.Permission) diag.Diagnostics {
var diags diag.Diagnostics
// Check the permissions in the workspace and see if they are all set in the bundle.
ok, missing := containsAll(p.Permissions, perms)
if !ok {
diags = diags.Append(diag.Diagnostic{
Severity: diag.Warning,
Summary: "workspace folder has permissions not configured in bundle",
Detail: fmt.Sprintf(
"The following permissions apply to the workspace folder at %q "+
"but are not configured in the bundle:\n%s\n"+
"Add them to your bundle permissions or remove them from the folder.\n"+
"See https://docs.databricks.com/dev-tools/bundles/permissions",
p.Path, toString(missing)),
})
}
return diags
}
// samePrincipal checks if two permissions refer to the same user/group/service principal.
func samePrincipal(a, b resources.Permission) bool {
return a.UserName == b.UserName &&
a.GroupName == b.GroupName &&
a.ServicePrincipalName == b.ServicePrincipalName
}
// containsAll checks if all permissions in permA (workspace) are accounted for in permB (bundle).
// A workspace permission is considered accounted for if the bundle has the same principal
// with an equal or higher permission level.
func containsAll(permA, permB []resources.Permission) (bool, []resources.Permission) {
var missing []resources.Permission
for _, a := range permA {
found := false
for _, b := range permB {
if samePrincipal(a, b) && resources.GetLevelScore(string(b.Level)) >= resources.GetLevelScore(string(a.Level)) {
found = true
break
}
}
if !found {
missing = append(missing, a)
}
}
return len(missing) == 0, missing
}
// convertWorkspaceObjectPermissionLevel converts matching object permission levels to bundle ones.
// If there is no matching permission level, it returns permission level as is, for example, CAN_EDIT.
func convertWorkspaceObjectPermissionLevel(level workspace.WorkspaceObjectPermissionLevel) string {
switch level {
case workspace.WorkspaceObjectPermissionLevelCanRead:
return CAN_VIEW
default:
return string(level)
}
}
func toString(p []resources.Permission) string {
var sb strings.Builder
for _, perm := range p {
sb.WriteString(fmt.Sprintf("- %s\n", perm.String()))
}
return sb.String()
}