Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions acceptance/acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,22 @@ func TestInprocessMode(t *testing.T) {
require.Equal(t, 1, testAccept(t, true, "selftest/server"))
}

// Configure replacements for environment variables we read from test environments.
func setReplsForTestEnvVars(t *testing.T, repls *testdiff.ReplacementsContext) {
envVars := []string{
"TEST_USER_EMAIL",
"TEST_GROUP_NAME",
"TEST_SP_APPLICATION_ID",
"TEST_DEFAULT_WAREHOUSE_ID",
"TEST_INSTANCE_POOL_ID",
}
for _, envVar := range envVars {
if value := os.Getenv(envVar); value != "" {
repls.Set(value, "["+envVar+"]")
}
}
}

func testAccept(t *testing.T, inprocessMode bool, singleTest string) int {
repls := testdiff.ReplacementsContext{}
cwd, err := os.Getwd()
Expand Down Expand Up @@ -234,10 +250,7 @@ func testAccept(t *testing.T, inprocessMode bool, singleTest string) int {
}
}

testDefaultWarehouseId := os.Getenv("TEST_DEFAULT_WAREHOUSE_ID")
if testDefaultWarehouseId != "" {
repls.Set(testDefaultWarehouseId, "[TEST_DEFAULT_WAREHOUSE_ID]")
}
setReplsForTestEnvVars(t, &repls)

terraformrcPath := filepath.Join(terraformDir, ".terraformrc")
t.Setenv("TF_CLI_CONFIG_FILE", terraformrcPath)
Expand All @@ -252,8 +265,6 @@ func testAccept(t *testing.T, inprocessMode bool, singleTest string) int {
// do it last so that full paths match first:
repls.SetPath(buildDir, "[BUILD_DIR]")

repls.Set(os.Getenv("TEST_INSTANCE_POOL_ID"), "[TEST_INSTANCE_POOL_ID]")

testdiff.PrepareReplacementsDevVersion(t, &repls)
testdiff.PrepareReplacementSdkVersion(t, &repls)
testdiff.PrepareReplacementsGoVersion(t, &repls)
Expand Down
7 changes: 7 additions & 0 deletions acceptance/bundle/refschema/out.fields.txt
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,13 @@ resources.dashboards.*.serialized_dashboard string ALL
resources.dashboards.*.update_time string ALL
resources.dashboards.*.url string INPUT
resources.dashboards.*.warehouse_id string ALL
resources.dashboards.*.permissions.object_id string ALL
resources.dashboards.*.permissions.permissions []iam.AccessControlRequest ALL
resources.dashboards.*.permissions.permissions[*] iam.AccessControlRequest ALL
resources.dashboards.*.permissions.permissions[*].group_name string ALL
resources.dashboards.*.permissions.permissions[*].permission_level iam.PermissionLevel ALL
resources.dashboards.*.permissions.permissions[*].service_principal_name string ALL
resources.dashboards.*.permissions.permissions[*].user_name string ALL
resources.database_catalogs.*.create_database_if_not_exists bool ALL
resources.database_catalogs.*.database_instance_name string ALL
resources.database_catalogs.*.database_name string ALL
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
bundle:
name: dashboard-perm-$UNIQUE_NAME

resources:
dashboards:
foo:
display_name: test-dashboard-$UNIQUE_NAME
warehouse_id: $TEST_DEFAULT_WAREHOUSE_ID
parent_path: /Users/$CURRENT_USER_NAME/folder1
serialized_dashboard: '{"pages":[{"name":"page1","displayName":"Page 1"}]}'
permissions:
- level: CAN_READ
user_name: $TEST_USER_EMAIL
- level: CAN_MANAGE
group_name: $TEST_GROUP_NAME
- level: CAN_MANAGE
service_principal_name: $TEST_SP_APPLICATION_ID
- level: CAN_MANAGE
user_name: $CURRENT_USER_NAME
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"plan": {
"resources.dashboards.foo": {
"action": "create",
"new_state": {
"config": {
"display_name": "test-dashboard-[UNIQUE_NAME]",
"parent_path": "/Users/[USERNAME]/folder1",
"warehouse_id": "[TEST_DEFAULT_WAREHOUSE_ID]"
}
}
},
"resources.dashboards.foo.permissions": {
"depends_on": [
{
"node": "resources.dashboards.foo",
"label": "${resources.dashboards.foo.id}"
}
],
"action": "create",
"new_state": {
"config": {
"object_id": "",
"permissions": [
{
"permission_level": "CAN_READ",
"user_name": "[TEST_USER_EMAIL]"
},
{
"group_name": "[TEST_GROUP_NAME]",
"permission_level": "CAN_MANAGE"
},
{
"permission_level": "CAN_MANAGE",
"service_principal_name": "[TEST_SP_APPLICATION_ID]"
},
{
"permission_level": "CAN_MANAGE",
"user_name": "[USERNAME]"
}
]
},
"vars": {
"object_id": "/dashboards/${resources.dashboards.foo.id}"
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"plan": {
"resources.dashboards.foo": {
"action": "create"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"method": "PUT",
"path": "/api/2.0/permissions/dashboards/[DASHBOARD_ID]",
"body": {
"access_control_list": [
{
"permission_level": "CAN_READ",
"user_name": "[TEST_USER_EMAIL]"
},
{
"group_name": "[TEST_GROUP_NAME]",
"permission_level": "CAN_MANAGE"
},
{
"permission_level": "CAN_MANAGE",
"service_principal_name": "[TEST_SP_APPLICATION_ID]"
},
{
"permission_level": "CAN_MANAGE",
"user_name": "[USERNAME]"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"method": "PUT",
"path": "/api/2.0/permissions/dashboards/[DASHBOARD_ID]",
"body": {
"access_control_list": [
{
"permission_level": "CAN_MANAGE",
"service_principal_name": "[TEST_SP_APPLICATION_ID]"
},
{
"group_name": "[TEST_GROUP_NAME]",
"permission_level": "CAN_MANAGE"
},
{
"permission_level": "CAN_MANAGE",
"user_name": "[USERNAME]"
},
{
"permission_level": "CAN_READ",
"user_name": "[TEST_USER_EMAIL]"
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"method": "PUT",
"path": "/api/2.0/permissions/dashboards/[DASHBOARD_ID]",
"body": {}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

>>> [CLI] bundle validate -o json
[
{
"level": "CAN_READ",
"user_name": "[TEST_USER_EMAIL]"
},
{
"group_name": "[TEST_GROUP_NAME]",
"level": "CAN_MANAGE"
},
{
"level": "CAN_MANAGE",
"service_principal_name": "[TEST_SP_APPLICATION_ID]"
},
{
"level": "CAN_MANAGE",
"user_name": "[USERNAME]"
}
]

>>> [CLI] bundle deploy
Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/dashboard-perm-[UNIQUE_NAME]/default/files...
Deploying resources...
Updating deployment state...
Deployment complete!

>>> [CLI] bundle destroy --auto-approve
The following resources will be deleted:
delete dashboard foo

All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/dashboard-perm-[UNIQUE_NAME]/default

Deleting files...
Destroy complete!
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
if [ -z "$CLOUD_ENV" ]; then
export TEST_USER_EMAIL="[email protected]"
export TEST_GROUP_NAME="data-team"
export TEST_SP_APPLICATION_ID="f37d18cd-98a8-4db5-8112-12dd0a6bfe38"

echo "$TEST_USER_EMAIL:TEST_USER_EMAIL" >> ACC_REPLS
echo "$TEST_GROUP_NAME:TEST_GROUP_NAME" >> ACC_REPLS
echo "$TEST_SP_APPLICATION_ID:TEST_SP_APPLICATION_ID" >> ACC_REPLS
fi

envsubst < databricks.yml.tmpl > databricks.yml

trace $CLI bundle validate -o json | jq .resources.dashboards.foo.permissions
rm out.requests.txt

$CLI bundle debug plan > out.plan.$DATABRICKS_BUNDLE_ENGINE.json

rm out.requests.txt
trace $CLI bundle deploy

dashboard_id=$($CLI bundle summary --output json | jq -r '.resources.dashboards.foo.id')
echo "$dashboard_id:DASHBOARD_ID" >> ACC_REPLS

print_requests.py //permissions > out.requests.deploy.$DATABRICKS_BUNDLE_ENGINE.json

trace $CLI bundle destroy --auto-approve
print_requests.py //permissions > out.requests.destroy.$DATABRICKS_BUNDLE_ENGINE.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Local = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not run this test locally?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cloud identity is a service principal, but the local identity is a username. That shows up in the permissions request body.

It was easiest to just run the test on the cloud. Otherwise we'll need separate golden files for local and cloud.

Copy link
Contributor

@denik denik Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have IsServicePrincipal = true setting in test.toml for such cases. This makes test runner set up service-principal-like identity locally.

RequiresWarehouse = true
Cloud = true
12 changes: 12 additions & 0 deletions acceptance/bundle/resources/permissions/output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ DIFF clusters/current_can_manage/out.requests.destroy.direct.json
+ "path": "/api/2.0/permissions/clusters/[UUID]"
+ }
+]
MATCH dashboards/create/out.requests.deploy.direct.json
DIFF dashboards/create/out.requests.destroy.direct.json
--- dashboards/create/out.requests.destroy.direct.json
+++ dashboards/create/out.requests.destroy.terraform.json
@@ -1 +1,7 @@
-[]+[
+ {
+ "body": {},
+ "method": "PUT",
+ "path": "/api/2.0/permissions/dashboards/[DASHBOARD_ID]"
+ }
+]
MATCH database_instances/current_can_manage/out.requests.deploy.direct.json
DIFF database_instances/current_can_manage/out.requests.destroy.direct.json
--- database_instances/current_can_manage/out.requests.destroy.direct.json
Expand Down
1 change: 1 addition & 0 deletions bundle/direct/dresources/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var SupportedResources = map[string]any{
"jobs.permissions": (*ResourcePermissions)(nil),
"pipelines.permissions": (*ResourcePermissions)(nil),
"apps.permissions": (*ResourcePermissions)(nil),
"dashboards.permissions": (*ResourcePermissions)(nil),
"clusters.permissions": (*ResourcePermissions)(nil),
"database_instances.permissions": (*ResourcePermissions)(nil),
"experiments.permissions": (*ResourcePermissions)(nil),
Expand Down
31 changes: 31 additions & 0 deletions bundle/direct/dresources/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/databricks/databricks-sdk-go"
"github.com/databricks/databricks-sdk-go/service/apps"
"github.com/databricks/databricks-sdk-go/service/catalog"
"github.com/databricks/databricks-sdk-go/service/dashboards"
"github.com/databricks/databricks-sdk-go/service/database"
"github.com/databricks/databricks-sdk-go/service/iam"
"github.com/databricks/databricks-sdk-go/service/jobs"
Expand Down Expand Up @@ -252,6 +253,36 @@ var testDeps = map[string]prepareWorkspace{
}},
}, nil
},

"dashboards.permissions": func(client *databricks.WorkspaceClient) (any, error) {
ctx := context.Background()
parentPath := "/Workspace/Users/[email protected]"

// Create parent directory if it doesn't exist
err := client.Workspace.MkdirsByPath(ctx, parentPath)
if err != nil {
return nil, err
}

resp, err := client.Lakeview.Create(ctx, dashboards.CreateDashboardRequest{
Dashboard: dashboards.Dashboard{
DisplayName: "dashboard-permissions",
ParentPath: parentPath,
SerializedDashboard: `{"pages":[{"name":"page1","displayName":"Page 1"}]}`,
},
})
if err != nil {
return nil, err
}

return &PermissionsState{
ObjectID: "/dashboards/" + resp.DashboardId,
Permissions: []iam.AccessControlRequest{{
PermissionLevel: "CAN_MANAGE",
UserName: "[email protected]",
}},
}, nil
},
}

func TestAll(t *testing.T) {
Expand Down