Skip to content

Commit 41b19bb

Browse files
committed
bundle: reject genie_space permissions during plan
Databricks workspaces do not expose a permissions endpoint for Genie Spaces (PUT /permissions/genie/spaces/<id> returns 404 ENDPOINT_NOT_FOUND). Without an upfront check the deploy creates the space first and then errors when applying permissions, leaving partial state behind. Add ValidateGenieSpacePermissions to the PreDeployChecks pipeline so both per-resource permissions and bundle-level permissions propagated by ApplyBundlePermissions surface a clear validation error before any API call is made. Co-authored-by: Isaac
1 parent 1706660 commit 41b19bb

8 files changed

Lines changed: 156 additions & 0 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
bundle:
2+
name: genie-space-permissions-unsupported
3+
4+
resources:
5+
genie_spaces:
6+
inline_perms:
7+
title: "Inline Perms"
8+
warehouse_id: "test-warehouse-id"
9+
serialized_space: "{}"
10+
permissions:
11+
- level: CAN_MANAGE
12+
user_name: someone@example.com
13+
14+
bundle_perms:
15+
title: "Bundle Perms"
16+
warehouse_id: "test-warehouse-id"
17+
serialized_space: "{}"
18+
19+
permissions:
20+
- level: CAN_MANAGE
21+
user_name: someone@example.com

acceptance/bundle/validate/genie_space_permissions_unsupported/out.test.toml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Recommendation: permissions section should explicitly include the current deployment identity '[USERNAME]' or one of its groups
2+
If it is not included, CAN_MANAGE permissions are only applied if the present identity is used to deploy.
3+
4+
Consider using a adding a top-level permissions section such as the following:
5+
6+
permissions:
7+
- user_name: [USERNAME]
8+
level: CAN_MANAGE
9+
10+
See https://docs.databricks.com/dev-tools/bundles/permissions.html to learn more about permission configuration.
11+
in databricks.yml:20:3
12+
13+
Error: Genie Space permissions are not supported
14+
15+
Databricks workspaces do not expose a permissions endpoint for Genie Spaces, so a deploy with permissions configured would create the space and then fail. Remove the permissions block, or remove the Genie Space from any bundle-level permissions, until the API adds support.
16+
17+
Error: Genie Space permissions are not supported
18+
19+
Databricks workspaces do not expose a permissions endpoint for Genie Spaces, so a deploy with permissions configured would create the space and then fail. Remove the permissions block, or remove the Genie Space from any bundle-level permissions, until the API adds support.
20+
21+
22+
Exit code: 1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$CLI bundle plan
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Local = true
2+
Cloud = false
3+
4+
Ignore = [".databricks"]
5+
6+
# Genie spaces only support direct deployment engine.
7+
[EnvMatrix]
8+
DATABRICKS_BUNDLE_ENGINE = ["direct"]
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package mutator
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/databricks/cli/bundle"
8+
"github.com/databricks/cli/libs/diag"
9+
)
10+
11+
type validateGenieSpacePermissions struct{}
12+
13+
// ValidateGenieSpacePermissions errors if any genie_space resource has
14+
// permissions configured. The Databricks workspace API does not expose
15+
// PUT /permissions/genie/spaces/<id>, so the deploy would create the
16+
// space and then fail when applying permissions, leaving partial state.
17+
// Bundle-level permissions are propagated to genie_spaces by
18+
// ApplyBundlePermissions and are caught here as well.
19+
func ValidateGenieSpacePermissions() bundle.Mutator {
20+
return &validateGenieSpacePermissions{}
21+
}
22+
23+
func (m *validateGenieSpacePermissions) Name() string {
24+
return "ValidateGenieSpacePermissions"
25+
}
26+
27+
func (m *validateGenieSpacePermissions) Apply(_ context.Context, b *bundle.Bundle) diag.Diagnostics {
28+
var diags diag.Diagnostics
29+
30+
for key, space := range b.Config.Resources.GenieSpaces {
31+
if space == nil || len(space.Permissions) == 0 {
32+
continue
33+
}
34+
35+
diags = diags.Append(diag.Diagnostic{
36+
Severity: diag.Error,
37+
Summary: "Genie Space permissions are not supported",
38+
Detail: "Databricks workspaces do not expose a permissions endpoint for Genie Spaces, so a deploy with permissions configured would create the space and then fail. Remove the permissions block, or remove the Genie Space from any bundle-level permissions, until the API adds support.",
39+
Locations: b.Config.GetLocations(fmt.Sprintf("resources.genie_spaces.%s.permissions", key)),
40+
})
41+
}
42+
43+
return diags
44+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package mutator_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/databricks/cli/bundle"
7+
"github.com/databricks/cli/bundle/config"
8+
"github.com/databricks/cli/bundle/config/mutator"
9+
"github.com/databricks/cli/bundle/config/resources"
10+
"github.com/databricks/databricks-sdk-go/service/iam"
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func TestValidateGenieSpacePermissions_NoPermissions(t *testing.T) {
15+
b := &bundle.Bundle{
16+
Config: config.Root{
17+
Resources: config.Resources{
18+
GenieSpaces: map[string]*resources.GenieSpace{
19+
"my_space": {
20+
GenieSpaceConfig: resources.GenieSpaceConfig{
21+
Title: "My Space",
22+
},
23+
},
24+
},
25+
},
26+
},
27+
}
28+
29+
diags := bundle.Apply(t.Context(), b, mutator.ValidateGenieSpacePermissions())
30+
assert.Empty(t, diags)
31+
}
32+
33+
func TestValidateGenieSpacePermissions_WithPermissionsErrors(t *testing.T) {
34+
b := &bundle.Bundle{
35+
Config: config.Root{
36+
Resources: config.Resources{
37+
GenieSpaces: map[string]*resources.GenieSpace{
38+
"my_space": {
39+
GenieSpaceConfig: resources.GenieSpaceConfig{
40+
Title: "My Space",
41+
},
42+
Permissions: []resources.Permission{
43+
{Level: iam.PermissionLevel("CAN_MANAGE"), UserName: "user@example.com"},
44+
},
45+
},
46+
},
47+
},
48+
},
49+
}
50+
51+
diags := bundle.Apply(t.Context(), b, mutator.ValidateGenieSpacePermissions())
52+
assert.Len(t, diags, 1)
53+
assert.Equal(t, "Genie Space permissions are not supported", diags[0].Summary)
54+
}

bundle/phases/plan.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ func PreDeployChecks(ctx context.Context, b *bundle.Bundle, isPlan bool, engine
2525
deploy.StatePull(),
2626
mutator.ValidateGitDetails(),
2727
mutator.ValidateDirectOnlyResources(engine),
28+
mutator.ValidateGenieSpacePermissions(),
2829
mutator.ValidateLifecycleStarted(engine),
2930
statemgmt.CheckRunningResource(engine),
3031
)

0 commit comments

Comments
 (0)