From 20933fcb36526b7bea36d8808fee8a3c7223da51 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 27 Oct 2026 12:29:16 +0100 Subject: [PATCH 1/8] Don't clear app user_api_scopes on unrelated updates The direct engine always sent user_api_scopes in the Apps update_mask, so any update (e.g. a description change) cleared scopes that cannot be set through this API, such as "jobs" added at the account level. Now user_api_scopes is only in the mask when the bundle changes it, and remote-only drift on it is ignored. The testserver now clears masked fields that are absent from the body, like the real API. Co-authored-by: Isaac --- .../apps/lifecycle-started/output.txt | 4 +- .../apps/update-omitted-scopes/app/app.py | 1 + .../apps/update-omitted-scopes/databricks.yml | 9 +++ .../update-omitted-scopes/out.requests.json | 25 +++++++ .../apps/update-omitted-scopes/out.test.toml | 2 + .../apps/update-omitted-scopes/output.txt | 39 +++++++++++ .../apps/update-omitted-scopes/script | 17 +++++ .../apps/update-omitted-scopes/test.toml | 2 + .../apps/update-preserves-scopes/app/app.py | 1 + .../update-preserves-scopes/databricks.yml | 10 +++ .../update-preserves-scopes/out.requests.json | 30 ++++++++ .../update-preserves-scopes/out.test.toml | 2 + .../apps/update-preserves-scopes/output.txt | 68 +++++++++++++++++++ .../apps/update-preserves-scopes/script | 27 ++++++++ .../apps/update-preserves-scopes/test.toml | 2 + .../resources/apps/update/out.requests.json | 2 +- bundle/direct/dresources/app.go | 16 ++++- bundle/direct/dresources/configs/apps.yml | 4 ++ libs/testserver/apps.go | 13 +++- 19 files changed, 267 insertions(+), 7 deletions(-) create mode 100644 acceptance/bundle/resources/apps/update-omitted-scopes/app/app.py create mode 100644 acceptance/bundle/resources/apps/update-omitted-scopes/databricks.yml create mode 100644 acceptance/bundle/resources/apps/update-omitted-scopes/out.requests.json create mode 100644 acceptance/bundle/resources/apps/update-omitted-scopes/out.test.toml create mode 100644 acceptance/bundle/resources/apps/update-omitted-scopes/output.txt create mode 100644 acceptance/bundle/resources/apps/update-omitted-scopes/script create mode 100644 acceptance/bundle/resources/apps/update-omitted-scopes/test.toml create mode 100644 acceptance/bundle/resources/apps/update-preserves-scopes/app/app.py create mode 100644 acceptance/bundle/resources/apps/update-preserves-scopes/databricks.yml create mode 100644 acceptance/bundle/resources/apps/update-preserves-scopes/out.requests.json create mode 100644 acceptance/bundle/resources/apps/update-preserves-scopes/out.test.toml create mode 100644 acceptance/bundle/resources/apps/update-preserves-scopes/output.txt create mode 100644 acceptance/bundle/resources/apps/update-preserves-scopes/script create mode 100644 acceptance/bundle/resources/apps/update-preserves-scopes/test.toml diff --git a/acceptance/bundle/resources/apps/lifecycle-started/output.txt b/acceptance/bundle/resources/apps/lifecycle-started/output.txt index 05c88f1cd78..799ea1aaec0 100644 --- a/acceptance/bundle/resources/apps/lifecycle-started/output.txt +++ b/acceptance/bundle/resources/apps/lifecycle-started/output.txt @@ -90,7 +90,7 @@ Resources: 0 created, 1 changed, 0 deleted, 0 unchanged "description": "MY_APP_DESCRIPTION_2", "name": "[UNIQUE_NAME]" }, - "update_mask": "description,budget_policy_id,usage_policy_id,resources,user_api_scopes,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" + "update_mask": "description,budget_policy_id,usage_policy_id,resources,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" } } @@ -117,7 +117,7 @@ Resources: 0 created, 1 changed, 0 deleted, 0 unchanged "description": "MY_APP_DESCRIPTION_3", "name": "[UNIQUE_NAME]" }, - "update_mask": "description,budget_policy_id,usage_policy_id,resources,user_api_scopes,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" + "update_mask": "description,budget_policy_id,usage_policy_id,resources,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" } } { diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/app/app.py b/acceptance/bundle/resources/apps/update-omitted-scopes/app/app.py new file mode 100644 index 00000000000..f1a18139c84 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/app/app.py @@ -0,0 +1 @@ +print("Hello world!") diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/databricks.yml b/acceptance/bundle/resources/apps/update-omitted-scopes/databricks.yml new file mode 100644 index 00000000000..6a74ae8e35a --- /dev/null +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/databricks.yml @@ -0,0 +1,9 @@ +bundle: + name: test-bundle + +resources: + apps: + mykey: + name: myappname + description: my_app_description + source_code_path: ./app diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/out.requests.json b/acceptance/bundle/resources/apps/update-omitted-scopes/out.requests.json new file mode 100644 index 00000000000..6b520b169b4 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/out.requests.json @@ -0,0 +1,25 @@ +{ + "method": "POST", + "path": "/api/2.0/apps/myappname/update", + "body": { + "app": { + "name": "myappname", + "user_api_scopes": [ + "sql", + "jobs" + ] + }, + "update_mask": "user_api_scopes" + } +} +{ + "method": "POST", + "path": "/api/2.0/apps/myappname/update", + "body": { + "app": { + "description": "MY_APP_DESCRIPTION", + "name": "myappname" + }, + "update_mask": "description,budget_policy_id,usage_policy_id,resources,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" + } +} diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/out.test.toml b/acceptance/bundle/resources/apps/update-omitted-scopes/out.test.toml new file mode 100644 index 00000000000..a927a5fbc06 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/out.test.toml @@ -0,0 +1,2 @@ +Cloud = false +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt b/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt new file mode 100644 index 00000000000..689478e0cd7 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt @@ -0,0 +1,39 @@ + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files... +Created apps.mykey +Files: 2 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged + +>>> print_requests + +=== Out-of-band: set scopes on an app whose bundle does not declare any +>>> [CLI] api post /api/2.0/apps/myappname/update --json {"app": {"name": "myappname", "user_api_scopes": ["sql", "jobs"]}, "update_mask": "user_api_scopes"} + +=== Change description and re-deploy; user_api_scopes must not be in the update mask +>>> update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files... +Updated apps.mykey +Files: 1 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged + +>>> print_requests + +>>> [CLI] apps get myappname +{ + "description": "MY_APP_DESCRIPTION", + "user_api_scopes": [ + "sql", + "jobs" + ] +} + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.apps.mykey + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/script b/acceptance/bundle/resources/apps/update-omitted-scopes/script new file mode 100644 index 00000000000..130dca3489d --- /dev/null +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/script @@ -0,0 +1,17 @@ +print_requests() { + print_requests.py //apps '^//api/2.0/bundle' --del-body url +} + +trace $CLI bundle deploy +trace print_requests > /dev/null + +title "Out-of-band: set scopes on an app whose bundle does not declare any" +trace $CLI api post /api/2.0/apps/myappname/update --json '{"app": {"name": "myappname", "user_api_scopes": ["sql", "jobs"]}, "update_mask": "user_api_scopes"}' > /dev/null + +title "Change description and re-deploy; user_api_scopes must not be in the update mask" +trace update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION +trace $CLI bundle deploy +trace print_requests > out.requests.json +trace $CLI apps get myappname | jq '{description, user_api_scopes}' + +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml b/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml new file mode 100644 index 00000000000..474ccd75b48 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml @@ -0,0 +1,2 @@ +Cloud = false # jobs scope can only be added with account-admin privileges +Ignore = [".databricks", "databricks.yml"] diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/app/app.py b/acceptance/bundle/resources/apps/update-preserves-scopes/app/app.py new file mode 100644 index 00000000000..f1a18139c84 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/app/app.py @@ -0,0 +1 @@ +print("Hello world!") diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/databricks.yml b/acceptance/bundle/resources/apps/update-preserves-scopes/databricks.yml new file mode 100644 index 00000000000..ba2dca0ddfc --- /dev/null +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/databricks.yml @@ -0,0 +1,10 @@ +bundle: + name: test-bundle + +resources: + apps: + mykey: + name: myappname + description: my_app_description + source_code_path: ./app + user_api_scopes: [sql, files.files] diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/out.requests.json b/acceptance/bundle/resources/apps/update-preserves-scopes/out.requests.json new file mode 100644 index 00000000000..f725c40f7c1 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/out.requests.json @@ -0,0 +1,30 @@ +{ + "method": "POST", + "path": "/api/2.0/apps/myappname/update", + "body": { + "app": { + "description": "MY_APP_DESCRIPTION", + "name": "myappname", + "user_api_scopes": [ + "sql", + "files.files" + ] + }, + "update_mask": "description,budget_policy_id,usage_policy_id,resources,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" + } +} +{ + "method": "POST", + "path": "/api/2.0/apps/myappname/update", + "body": { + "app": { + "description": "MY_APP_DESCRIPTION", + "name": "myappname", + "user_api_scopes": [ + "sql", + "iam.access-control:read" + ] + }, + "update_mask": "description,budget_policy_id,usage_policy_id,resources,user_api_scopes,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" + } +} diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/out.test.toml b/acceptance/bundle/resources/apps/update-preserves-scopes/out.test.toml new file mode 100644 index 00000000000..a927a5fbc06 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/out.test.toml @@ -0,0 +1,2 @@ +Cloud = false +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/output.txt b/acceptance/bundle/resources/apps/update-preserves-scopes/output.txt new file mode 100644 index 00000000000..a55a33dfba4 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/output.txt @@ -0,0 +1,68 @@ + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files... +Created apps.mykey +Files: 2 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged + +=== Out-of-band: add a scope the bundle cannot declare (e.g. via account-level update) +>>> [CLI] api post /api/2.0/apps/myappname/update --json {"app": {"name": "myappname", "user_api_scopes": ["sql", "files.files", "jobs"]}, "update_mask": "user_api_scopes"} + +>>> [CLI] apps get myappname +[ + "sql", + "files.files", + "jobs" +] + +=== Plan after out-of-band change +>>> [CLI] bundle plan +Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged + +=== Change description and re-deploy; the update must only touch description +>>> update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION + +>>> print_requests + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files... +Updated apps.mykey +Files: 1 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged + +>>> print_requests + +>>> [CLI] apps get myappname +{ + "description": "MY_APP_DESCRIPTION", + "user_api_scopes": [ + "sql", + "files.files", + "jobs" + ] +} + +=== Change the declared scopes; they are written in full, replacing the remote value +>>> update_file.py databricks.yml [sql, files.files] [sql, iam.access-control:read] + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files... +Updated apps.mykey +Files: 2 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged + +>>> print_requests + +>>> [CLI] apps get myappname +[ + "sql", + "iam.access-control:read" +] + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.apps.mykey + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/script b/acceptance/bundle/resources/apps/update-preserves-scopes/script new file mode 100644 index 00000000000..aaca858dd1b --- /dev/null +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/script @@ -0,0 +1,27 @@ +print_requests() { + print_requests.py //apps '^//api/2.0/bundle' --del-body url +} + +trace $CLI bundle deploy + +title "Out-of-band: add a scope the bundle cannot declare (e.g. via account-level update)" +trace $CLI api post /api/2.0/apps/myappname/update --json '{"app": {"name": "myappname", "user_api_scopes": ["sql", "files.files", "jobs"]}, "update_mask": "user_api_scopes"}' > /dev/null +trace $CLI apps get myappname | jq .user_api_scopes + +title "Plan after out-of-band change" +trace $CLI bundle plan + +title "Change description and re-deploy; the update must only touch description" +trace update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION +trace print_requests > /dev/null +trace $CLI bundle deploy +trace print_requests > out.requests.json +trace $CLI apps get myappname | jq '{description, user_api_scopes}' + +title "Change the declared scopes; they are written in full, replacing the remote value" +trace update_file.py databricks.yml "[sql, files.files]" "[sql, iam.access-control:read]" +trace $CLI bundle deploy +trace print_requests >> out.requests.json +trace $CLI apps get myappname | jq .user_api_scopes + +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/test.toml b/acceptance/bundle/resources/apps/update-preserves-scopes/test.toml new file mode 100644 index 00000000000..474ccd75b48 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/test.toml @@ -0,0 +1,2 @@ +Cloud = false # jobs scope can only be added with account-admin privileges +Ignore = [".databricks", "databricks.yml"] diff --git a/acceptance/bundle/resources/apps/update/out.requests.json b/acceptance/bundle/resources/apps/update/out.requests.json index e68269ec514..b3b05c6e140 100644 --- a/acceptance/bundle/resources/apps/update/out.requests.json +++ b/acceptance/bundle/resources/apps/update/out.requests.json @@ -17,7 +17,7 @@ "description": "MY_APP_DESCRIPTION", "name": "myappname" }, - "update_mask": "description,budget_policy_id,usage_policy_id,resources,user_api_scopes,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" + "update_mask": "description,budget_policy_id,usage_policy_id,resources,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" } } { diff --git a/bundle/direct/dresources/app.go b/bundle/direct/dresources/app.go index 22cd7cc2b4e..85fa5b38dbe 100644 --- a/bundle/direct/dresources/app.go +++ b/bundle/direct/dresources/app.go @@ -176,17 +176,31 @@ var UpdateMaskFields = []string{ "telemetry_export_destinations", } +const userApiScopes = "user_api_scopes" + var updateMask = strings.Join(UpdateMaskFields, ",") +// updateMaskWithoutScopes is updateMask minus user_api_scopes. +var updateMaskWithoutScopes = strings.Join(slices.DeleteFunc(slices.Clone(UpdateMaskFields), func(f string) bool { + return f == userApiScopes +}), ",") + func (r *ResourceApp) DoUpdate(ctx context.Context, id string, config *AppState, entry *PlanEntry) (*AppRemote, error) { // Deploy-only fields (source_code_path, config, git_source, lifecycle) are excluded // from the request body; see appRequestBody. if hasAppChanges(entry) { app := appRequestBody(config) + // Sending user_api_scopes in the mask clears it unless the body carries the full value, and + // some scopes (e.g. "jobs") can only be added outside this API. So only write it when the + // bundle changed it; remote-only drift is skipped (ignore_remote_changes). + mask := updateMaskWithoutScopes + if change := entry.Changes[userApiScopes]; change != nil && change.Action != deployplan.Skip { + mask = updateMask + } request := apps.AsyncUpdateAppRequest{ App: &app, AppName: id, - UpdateMask: updateMask, + UpdateMask: mask, } updateWaiter, err := r.client.Apps.CreateUpdate(ctx, request) if err != nil { diff --git a/bundle/direct/dresources/configs/apps.yml b/bundle/direct/dresources/configs/apps.yml index a6725316bec..7c5954d68c1 100644 --- a/bundle/direct/dresources/configs/apps.yml +++ b/bundle/direct/dresources/configs/apps.yml @@ -16,5 +16,9 @@ backend_defaults: - field: lifecycle - field: lifecycle.started ignore_remote_changes: + # Scopes can be added out-of-band (e.g. "jobs" via account-level custom-app-integration update, + # which a bundle cannot declare). Only apply user_api_scopes when the bundle config changes it. + - field: user_api_scopes + reason: managed - field: space # This field is not yet supported by Update APIs but exposed in the API spec. TODO: fix when update APIs supports it. reason: managed diff --git a/libs/testserver/apps.go b/libs/testserver/apps.go index c70115d060f..d6f302c4404 100644 --- a/libs/testserver/apps.go +++ b/libs/testserver/apps.go @@ -86,8 +86,12 @@ func (s *FakeWorkspace) AppsCreateUpdate(req Request, name string) Response { } for field := range strings.SplitSeq(updateReq.UpdateMask, ",") { - if v, ok := updateMap[strings.TrimSpace(field)]; ok { - existingMap[strings.TrimSpace(field)] = v + field = strings.TrimSpace(field) + // Like the real API, a masked field absent from the body is cleared. + if v, ok := updateMap[field]; ok { + existingMap[field] = v + } else { + delete(existingMap, field) } } @@ -95,9 +99,12 @@ func (s *FakeWorkspace) AppsCreateUpdate(req Request, name string) Response { if err != nil { return Response{Body: fmt.Sprintf("internal error: %s", err), StatusCode: http.StatusInternalServerError} } - if err := json.Unmarshal(merged, &existing); err != nil { + // Unmarshal into a fresh struct so that cleared fields are not retained. + var updated apps.App + if err := json.Unmarshal(merged, &updated); err != nil { return Response{Body: fmt.Sprintf("internal error: %s", err), StatusCode: http.StatusInternalServerError} } + existing = updated } setUcSecurableKinds(&existing) s.Apps[name] = existing From 09928e5fe14fdfd9a615b5afbf143f9dbeb83bc2 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 27 Oct 2026 12:29:52 +0100 Subject: [PATCH 2/8] Add changelog fragment Co-authored-by: Isaac --- .nextchanges/bundles/apps-user-api-scopes.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nextchanges/bundles/apps-user-api-scopes.md diff --git a/.nextchanges/bundles/apps-user-api-scopes.md b/.nextchanges/bundles/apps-user-api-scopes.md new file mode 100644 index 00000000000..db9df4b1ed5 --- /dev/null +++ b/.nextchanges/bundles/apps-user-api-scopes.md @@ -0,0 +1 @@ +* Do not clear an app's `user_api_scopes` on updates that do not change them ([#7193](https://github.com/databricks/cli/pull/7193)). ([#7193](https://github.com/databricks/cli/pull/7193)) From 40e13753cb8a88bd45bdf34da494482233b72078 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 27 Oct 2026 12:31:28 +0100 Subject: [PATCH 3/8] Fix changelog fragment link format Co-authored-by: Isaac --- .nextchanges/bundles/apps-user-api-scopes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nextchanges/bundles/apps-user-api-scopes.md b/.nextchanges/bundles/apps-user-api-scopes.md index db9df4b1ed5..7e36c00f88d 100644 --- a/.nextchanges/bundles/apps-user-api-scopes.md +++ b/.nextchanges/bundles/apps-user-api-scopes.md @@ -1 +1 @@ -* Do not clear an app's `user_api_scopes` on updates that do not change them ([#7193](https://github.com/databricks/cli/pull/7193)). ([#7193](https://github.com/databricks/cli/pull/7193)) +* Do not clear an app's `user_api_scopes` on updates that do not change them. ([#7193](https://github.com/databricks/cli/pull/7193)) From 295488871a49ae718a4441046593b08d218eee74 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 27 Oct 2026 12:52:09 +0100 Subject: [PATCH 4/8] acc: Clear request log with rm and write one requests file per deploy Co-authored-by: Isaac --- .../out.deploy.requests.json | 11 +++++++++++ .../apps/update-omitted-scopes/output.txt | 2 -- .../resources/apps/update-omitted-scopes/script | 5 +++-- .../out.description.requests.json} | 14 ++------------ ...out.requests.json => out.scopes.requests.json} | 15 --------------- .../apps/update-preserves-scopes/output.txt | 2 -- .../resources/apps/update-preserves-scopes/script | 7 ++++--- 7 files changed, 20 insertions(+), 36 deletions(-) create mode 100644 acceptance/bundle/resources/apps/update-omitted-scopes/out.deploy.requests.json rename acceptance/bundle/resources/apps/{update-omitted-scopes/out.requests.json => update-preserves-scopes/out.description.requests.json} (68%) rename acceptance/bundle/resources/apps/update-preserves-scopes/{out.requests.json => out.scopes.requests.json} (51%) diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/out.deploy.requests.json b/acceptance/bundle/resources/apps/update-omitted-scopes/out.deploy.requests.json new file mode 100644 index 00000000000..a7255ff62c5 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/out.deploy.requests.json @@ -0,0 +1,11 @@ +{ + "method": "POST", + "path": "/api/2.0/apps/myappname/update", + "body": { + "app": { + "description": "MY_APP_DESCRIPTION", + "name": "myappname" + }, + "update_mask": "description,budget_policy_id,usage_policy_id,resources,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" + } +} diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt b/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt index 689478e0cd7..5750de86368 100644 --- a/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt @@ -5,8 +5,6 @@ Created apps.mykey Files: 2 uploaded, 0 deleted Resources: 1 created, 0 changed, 0 deleted, 0 unchanged ->>> print_requests - === Out-of-band: set scopes on an app whose bundle does not declare any >>> [CLI] api post /api/2.0/apps/myappname/update --json {"app": {"name": "myappname", "user_api_scopes": ["sql", "jobs"]}, "update_mask": "user_api_scopes"} diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/script b/acceptance/bundle/resources/apps/update-omitted-scopes/script index 130dca3489d..a57d5d8325f 100644 --- a/acceptance/bundle/resources/apps/update-omitted-scopes/script +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/script @@ -3,15 +3,16 @@ print_requests() { } trace $CLI bundle deploy -trace print_requests > /dev/null +rm "$OUT_REQUESTS" title "Out-of-band: set scopes on an app whose bundle does not declare any" trace $CLI api post /api/2.0/apps/myappname/update --json '{"app": {"name": "myappname", "user_api_scopes": ["sql", "jobs"]}, "update_mask": "user_api_scopes"}' > /dev/null +rm "$OUT_REQUESTS" title "Change description and re-deploy; user_api_scopes must not be in the update mask" trace update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION trace $CLI bundle deploy -trace print_requests > out.requests.json +trace print_requests > out.deploy.requests.json trace $CLI apps get myappname | jq '{description, user_api_scopes}' trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/out.requests.json b/acceptance/bundle/resources/apps/update-preserves-scopes/out.description.requests.json similarity index 68% rename from acceptance/bundle/resources/apps/update-omitted-scopes/out.requests.json rename to acceptance/bundle/resources/apps/update-preserves-scopes/out.description.requests.json index 6b520b169b4..55a172e4740 100644 --- a/acceptance/bundle/resources/apps/update-omitted-scopes/out.requests.json +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/out.description.requests.json @@ -3,23 +3,13 @@ "path": "/api/2.0/apps/myappname/update", "body": { "app": { + "description": "MY_APP_DESCRIPTION", "name": "myappname", "user_api_scopes": [ "sql", - "jobs" + "files.files" ] }, - "update_mask": "user_api_scopes" - } -} -{ - "method": "POST", - "path": "/api/2.0/apps/myappname/update", - "body": { - "app": { - "description": "MY_APP_DESCRIPTION", - "name": "myappname" - }, "update_mask": "description,budget_policy_id,usage_policy_id,resources,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" } } diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/out.requests.json b/acceptance/bundle/resources/apps/update-preserves-scopes/out.scopes.requests.json similarity index 51% rename from acceptance/bundle/resources/apps/update-preserves-scopes/out.requests.json rename to acceptance/bundle/resources/apps/update-preserves-scopes/out.scopes.requests.json index f725c40f7c1..40a2649e466 100644 --- a/acceptance/bundle/resources/apps/update-preserves-scopes/out.requests.json +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/out.scopes.requests.json @@ -1,18 +1,3 @@ -{ - "method": "POST", - "path": "/api/2.0/apps/myappname/update", - "body": { - "app": { - "description": "MY_APP_DESCRIPTION", - "name": "myappname", - "user_api_scopes": [ - "sql", - "files.files" - ] - }, - "update_mask": "description,budget_policy_id,usage_policy_id,resources,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" - } -} { "method": "POST", "path": "/api/2.0/apps/myappname/update", diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/output.txt b/acceptance/bundle/resources/apps/update-preserves-scopes/output.txt index a55a33dfba4..e33c9698156 100644 --- a/acceptance/bundle/resources/apps/update-preserves-scopes/output.txt +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/output.txt @@ -22,8 +22,6 @@ Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged === Change description and re-deploy; the update must only touch description >>> update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION ->>> print_requests - >>> [CLI] bundle deploy Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files... Updated apps.mykey diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/script b/acceptance/bundle/resources/apps/update-preserves-scopes/script index aaca858dd1b..107f919f0a9 100644 --- a/acceptance/bundle/resources/apps/update-preserves-scopes/script +++ b/acceptance/bundle/resources/apps/update-preserves-scopes/script @@ -3,25 +3,26 @@ print_requests() { } trace $CLI bundle deploy +rm "$OUT_REQUESTS" title "Out-of-band: add a scope the bundle cannot declare (e.g. via account-level update)" trace $CLI api post /api/2.0/apps/myappname/update --json '{"app": {"name": "myappname", "user_api_scopes": ["sql", "files.files", "jobs"]}, "update_mask": "user_api_scopes"}' > /dev/null trace $CLI apps get myappname | jq .user_api_scopes +rm "$OUT_REQUESTS" title "Plan after out-of-band change" trace $CLI bundle plan title "Change description and re-deploy; the update must only touch description" trace update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION -trace print_requests > /dev/null trace $CLI bundle deploy -trace print_requests > out.requests.json +trace print_requests > out.description.requests.json trace $CLI apps get myappname | jq '{description, user_api_scopes}' title "Change the declared scopes; they are written in full, replacing the remote value" trace update_file.py databricks.yml "[sql, files.files]" "[sql, iam.access-control:read]" trace $CLI bundle deploy -trace print_requests >> out.requests.json +trace print_requests > out.scopes.requests.json trace $CLI apps get myappname | jq .user_api_scopes trace $CLI bundle destroy --auto-approve From c80d638150319be200eb8e8a2130de5407c74967 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 27 Oct 2026 13:01:09 +0100 Subject: [PATCH 5/8] acc: Test removing user_api_scopes from config Co-authored-by: Isaac --- .../apps/update-removed-scopes/app/app.py | 1 + .../apps/update-removed-scopes/databricks.yml | 10 ++++++ .../out.deploy.requests.json | 11 +++++++ .../apps/update-removed-scopes/out.test.toml | 2 ++ .../apps/update-removed-scopes/output.txt | 33 +++++++++++++++++++ .../apps/update-removed-scopes/script | 15 +++++++++ .../apps/update-removed-scopes/test.toml | 2 ++ 7 files changed, 74 insertions(+) create mode 100644 acceptance/bundle/resources/apps/update-removed-scopes/app/app.py create mode 100644 acceptance/bundle/resources/apps/update-removed-scopes/databricks.yml create mode 100644 acceptance/bundle/resources/apps/update-removed-scopes/out.deploy.requests.json create mode 100644 acceptance/bundle/resources/apps/update-removed-scopes/out.test.toml create mode 100644 acceptance/bundle/resources/apps/update-removed-scopes/output.txt create mode 100644 acceptance/bundle/resources/apps/update-removed-scopes/script create mode 100644 acceptance/bundle/resources/apps/update-removed-scopes/test.toml diff --git a/acceptance/bundle/resources/apps/update-removed-scopes/app/app.py b/acceptance/bundle/resources/apps/update-removed-scopes/app/app.py new file mode 100644 index 00000000000..f1a18139c84 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-removed-scopes/app/app.py @@ -0,0 +1 @@ +print("Hello world!") diff --git a/acceptance/bundle/resources/apps/update-removed-scopes/databricks.yml b/acceptance/bundle/resources/apps/update-removed-scopes/databricks.yml new file mode 100644 index 00000000000..ba2dca0ddfc --- /dev/null +++ b/acceptance/bundle/resources/apps/update-removed-scopes/databricks.yml @@ -0,0 +1,10 @@ +bundle: + name: test-bundle + +resources: + apps: + mykey: + name: myappname + description: my_app_description + source_code_path: ./app + user_api_scopes: [sql, files.files] diff --git a/acceptance/bundle/resources/apps/update-removed-scopes/out.deploy.requests.json b/acceptance/bundle/resources/apps/update-removed-scopes/out.deploy.requests.json new file mode 100644 index 00000000000..77a445c3149 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-removed-scopes/out.deploy.requests.json @@ -0,0 +1,11 @@ +{ + "method": "POST", + "path": "/api/2.0/apps/myappname/update", + "body": { + "app": { + "description": "my_app_description", + "name": "myappname" + }, + "update_mask": "description,budget_policy_id,usage_policy_id,resources,user_api_scopes,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" + } +} diff --git a/acceptance/bundle/resources/apps/update-removed-scopes/out.test.toml b/acceptance/bundle/resources/apps/update-removed-scopes/out.test.toml new file mode 100644 index 00000000000..a927a5fbc06 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-removed-scopes/out.test.toml @@ -0,0 +1,2 @@ +Cloud = false +EnvMatrix.DMS = ["", "true"] diff --git a/acceptance/bundle/resources/apps/update-removed-scopes/output.txt b/acceptance/bundle/resources/apps/update-removed-scopes/output.txt new file mode 100644 index 00000000000..d58963a335f --- /dev/null +++ b/acceptance/bundle/resources/apps/update-removed-scopes/output.txt @@ -0,0 +1,33 @@ + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files... +Created apps.mykey +Files: 2 uploaded, 0 deleted +Resources: 1 created, 0 changed, 0 deleted, 0 unchanged + +=== Remove user_api_scopes from the config; the mask must include it with no value in the body +>>> update_file.py databricks.yml user_api_scopes: [sql, files.files] + +>>> [CLI] bundle plan +update apps.mykey + +Plan: 0 to add, 1 to change, 0 to delete, 0 unchanged + +>>> [CLI] bundle deploy +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-bundle/default/files... +Updated apps.mykey +Files: 1 uploaded, 0 deleted +Resources: 0 created, 1 changed, 0 deleted, 0 unchanged + +>>> print_requests + +>>> [CLI] apps get myappname +null + +>>> [CLI] bundle destroy --auto-approve +The following resources will be deleted: + delete resources.apps.mykey + +All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-bundle/default + +Destroy: 1 deleted diff --git a/acceptance/bundle/resources/apps/update-removed-scopes/script b/acceptance/bundle/resources/apps/update-removed-scopes/script new file mode 100644 index 00000000000..ef2f52d302d --- /dev/null +++ b/acceptance/bundle/resources/apps/update-removed-scopes/script @@ -0,0 +1,15 @@ +print_requests() { + print_requests.py //apps '^//api/2.0/bundle' --del-body url +} + +trace $CLI bundle deploy +rm "$OUT_REQUESTS" + +title "Remove user_api_scopes from the config; the mask must include it with no value in the body" +trace update_file.py databricks.yml "user_api_scopes: [sql, files.files]" "" +trace $CLI bundle plan +trace $CLI bundle deploy +trace print_requests > out.deploy.requests.json +trace $CLI apps get myappname | jq .user_api_scopes + +trace $CLI bundle destroy --auto-approve diff --git a/acceptance/bundle/resources/apps/update-removed-scopes/test.toml b/acceptance/bundle/resources/apps/update-removed-scopes/test.toml new file mode 100644 index 00000000000..00495bf9c14 --- /dev/null +++ b/acceptance/bundle/resources/apps/update-removed-scopes/test.toml @@ -0,0 +1,2 @@ +Cloud = false +Ignore = [".databricks", "databricks.yml"] From 3e77910916e83bc421a8b1dad7b532639beef6dc Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 27 Oct 2026 13:07:56 +0100 Subject: [PATCH 6/8] direct: always send declared user_api_scopes in app update mask Co-authored-by: Isaac --- .nextchanges/bundles/apps-user-api-scopes.md | 2 +- .../app/app.py | 0 .../databricks.yml | 0 .../out.description.requests.json | 2 +- .../out.scopes.requests.json | 0 .../out.test.toml | 0 .../output.txt | 7 +++---- .../script | 4 ++-- .../test.toml | 0 bundle/direct/dresources/app.go | 8 ++++---- bundle/direct/dresources/configs/apps.yml | 2 +- 11 files changed, 12 insertions(+), 13 deletions(-) rename acceptance/bundle/resources/apps/{update-preserves-scopes => update-declared-scopes}/app/app.py (100%) rename acceptance/bundle/resources/apps/{update-preserves-scopes => update-declared-scopes}/databricks.yml (100%) rename acceptance/bundle/resources/apps/{update-preserves-scopes => update-declared-scopes}/out.description.requests.json (70%) rename acceptance/bundle/resources/apps/{update-preserves-scopes => update-declared-scopes}/out.scopes.requests.json (100%) rename acceptance/bundle/resources/apps/{update-preserves-scopes => update-declared-scopes}/out.test.toml (100%) rename acceptance/bundle/resources/apps/{update-preserves-scopes => update-declared-scopes}/output.txt (90%) rename acceptance/bundle/resources/apps/{update-preserves-scopes => update-declared-scopes}/script (85%) rename acceptance/bundle/resources/apps/{update-preserves-scopes => update-declared-scopes}/test.toml (100%) diff --git a/.nextchanges/bundles/apps-user-api-scopes.md b/.nextchanges/bundles/apps-user-api-scopes.md index 7e36c00f88d..ffe71034788 100644 --- a/.nextchanges/bundles/apps-user-api-scopes.md +++ b/.nextchanges/bundles/apps-user-api-scopes.md @@ -1 +1 @@ -* Do not clear an app's `user_api_scopes` on updates that do not change them. ([#7193](https://github.com/databricks/cli/pull/7193)) +* Do not send an app's `user_api_scopes` in update requests unless the bundle declares or removes them, so scopes added outside the bundle are not cleared. ([#7193](https://github.com/databricks/cli/pull/7193)) diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/app/app.py b/acceptance/bundle/resources/apps/update-declared-scopes/app/app.py similarity index 100% rename from acceptance/bundle/resources/apps/update-preserves-scopes/app/app.py rename to acceptance/bundle/resources/apps/update-declared-scopes/app/app.py diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/databricks.yml b/acceptance/bundle/resources/apps/update-declared-scopes/databricks.yml similarity index 100% rename from acceptance/bundle/resources/apps/update-preserves-scopes/databricks.yml rename to acceptance/bundle/resources/apps/update-declared-scopes/databricks.yml diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/out.description.requests.json b/acceptance/bundle/resources/apps/update-declared-scopes/out.description.requests.json similarity index 70% rename from acceptance/bundle/resources/apps/update-preserves-scopes/out.description.requests.json rename to acceptance/bundle/resources/apps/update-declared-scopes/out.description.requests.json index 55a172e4740..16d08070af8 100644 --- a/acceptance/bundle/resources/apps/update-preserves-scopes/out.description.requests.json +++ b/acceptance/bundle/resources/apps/update-declared-scopes/out.description.requests.json @@ -10,6 +10,6 @@ "files.files" ] }, - "update_mask": "description,budget_policy_id,usage_policy_id,resources,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" + "update_mask": "description,budget_policy_id,usage_policy_id,resources,user_api_scopes,compute_size,compute_min_instances,compute_max_instances,git_repository,telemetry_export_destinations" } } diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/out.scopes.requests.json b/acceptance/bundle/resources/apps/update-declared-scopes/out.scopes.requests.json similarity index 100% rename from acceptance/bundle/resources/apps/update-preserves-scopes/out.scopes.requests.json rename to acceptance/bundle/resources/apps/update-declared-scopes/out.scopes.requests.json diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/out.test.toml b/acceptance/bundle/resources/apps/update-declared-scopes/out.test.toml similarity index 100% rename from acceptance/bundle/resources/apps/update-preserves-scopes/out.test.toml rename to acceptance/bundle/resources/apps/update-declared-scopes/out.test.toml diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/output.txt b/acceptance/bundle/resources/apps/update-declared-scopes/output.txt similarity index 90% rename from acceptance/bundle/resources/apps/update-preserves-scopes/output.txt rename to acceptance/bundle/resources/apps/update-declared-scopes/output.txt index e33c9698156..55553007373 100644 --- a/acceptance/bundle/resources/apps/update-preserves-scopes/output.txt +++ b/acceptance/bundle/resources/apps/update-declared-scopes/output.txt @@ -19,7 +19,7 @@ Resources: 1 created, 0 changed, 0 deleted, 0 unchanged >>> [CLI] bundle plan Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged -=== Change description and re-deploy; the update must only touch description +=== Change description and re-deploy; declared scopes are in the mask, so the remote value is replaced >>> update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION >>> [CLI] bundle deploy @@ -35,12 +35,11 @@ Resources: 0 created, 1 changed, 0 deleted, 0 unchanged "description": "MY_APP_DESCRIPTION", "user_api_scopes": [ "sql", - "files.files", - "jobs" + "files.files" ] } -=== Change the declared scopes; they are written in full, replacing the remote value +=== Change the declared scopes >>> update_file.py databricks.yml [sql, files.files] [sql, iam.access-control:read] >>> [CLI] bundle deploy diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/script b/acceptance/bundle/resources/apps/update-declared-scopes/script similarity index 85% rename from acceptance/bundle/resources/apps/update-preserves-scopes/script rename to acceptance/bundle/resources/apps/update-declared-scopes/script index 107f919f0a9..417375fb134 100644 --- a/acceptance/bundle/resources/apps/update-preserves-scopes/script +++ b/acceptance/bundle/resources/apps/update-declared-scopes/script @@ -13,13 +13,13 @@ rm "$OUT_REQUESTS" title "Plan after out-of-band change" trace $CLI bundle plan -title "Change description and re-deploy; the update must only touch description" +title "Change description and re-deploy; declared scopes are in the mask, so the remote value is replaced" trace update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION trace $CLI bundle deploy trace print_requests > out.description.requests.json trace $CLI apps get myappname | jq '{description, user_api_scopes}' -title "Change the declared scopes; they are written in full, replacing the remote value" +title "Change the declared scopes" trace update_file.py databricks.yml "[sql, files.files]" "[sql, iam.access-control:read]" trace $CLI bundle deploy trace print_requests > out.scopes.requests.json diff --git a/acceptance/bundle/resources/apps/update-preserves-scopes/test.toml b/acceptance/bundle/resources/apps/update-declared-scopes/test.toml similarity index 100% rename from acceptance/bundle/resources/apps/update-preserves-scopes/test.toml rename to acceptance/bundle/resources/apps/update-declared-scopes/test.toml diff --git a/bundle/direct/dresources/app.go b/bundle/direct/dresources/app.go index 85fa5b38dbe..a7042b0c776 100644 --- a/bundle/direct/dresources/app.go +++ b/bundle/direct/dresources/app.go @@ -190,11 +190,11 @@ func (r *ResourceApp) DoUpdate(ctx context.Context, id string, config *AppState, // from the request body; see appRequestBody. if hasAppChanges(entry) { app := appRequestBody(config) - // Sending user_api_scopes in the mask clears it unless the body carries the full value, and - // some scopes (e.g. "jobs") can only be added outside this API. So only write it when the - // bundle changed it; remote-only drift is skipped (ignore_remote_changes). + // Sending user_api_scopes in the mask clears it unless the body carries a value, and some + // scopes (e.g. "jobs") can only be added outside this API. So leave it out unless the + // bundle manages it: declares it, or removed it (the mask is what clears it). mask := updateMaskWithoutScopes - if change := entry.Changes[userApiScopes]; change != nil && change.Action != deployplan.Skip { + if change := entry.Changes[userApiScopes]; len(config.UserApiScopes) > 0 || (change != nil && change.Action != deployplan.Skip) { mask = updateMask } request := apps.AsyncUpdateAppRequest{ diff --git a/bundle/direct/dresources/configs/apps.yml b/bundle/direct/dresources/configs/apps.yml index 7c5954d68c1..1a86a6de78d 100644 --- a/bundle/direct/dresources/configs/apps.yml +++ b/bundle/direct/dresources/configs/apps.yml @@ -17,7 +17,7 @@ backend_defaults: - field: lifecycle.started ignore_remote_changes: # Scopes can be added out-of-band (e.g. "jobs" via account-level custom-app-integration update, - # which a bundle cannot declare). Only apply user_api_scopes when the bundle config changes it. + # which a bundle cannot declare). Remote-only drift alone does not plan an update. - field: user_api_scopes reason: managed - field: space # This field is not yet supported by Update APIs but exposed in the API spec. TODO: fix when update APIs supports it. From 606e8d7c8d483a266c756ff8981bb84b9711d297 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 27 Oct 2026 14:06:46 +0100 Subject: [PATCH 7/8] acc: Disable MSYS path conversion for api post in scopes tests Co-authored-by: Isaac --- .../bundle/resources/apps/update-declared-scopes/test.toml | 1 + acceptance/bundle/resources/apps/update-omitted-scopes/test.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/acceptance/bundle/resources/apps/update-declared-scopes/test.toml b/acceptance/bundle/resources/apps/update-declared-scopes/test.toml index 474ccd75b48..b84ce38cae8 100644 --- a/acceptance/bundle/resources/apps/update-declared-scopes/test.toml +++ b/acceptance/bundle/resources/apps/update-declared-scopes/test.toml @@ -1,2 +1,3 @@ +Env.MSYS_NO_PATHCONV = "1" Cloud = false # jobs scope can only be added with account-admin privileges Ignore = [".databricks", "databricks.yml"] diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml b/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml index 474ccd75b48..b84ce38cae8 100644 --- a/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml @@ -1,2 +1,3 @@ +Env.MSYS_NO_PATHCONV = "1" Cloud = false # jobs scope can only be added with account-admin privileges Ignore = [".databricks", "databricks.yml"] From 95dcba43b1d8088161c7e94f023e315da826c16f Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 27 Oct 2026 14:25:43 +0100 Subject: [PATCH 8/8] acc: Scope MSYS_NO_PATHCONV to the api post calls Co-authored-by: Isaac --- .../bundle/resources/apps/update-declared-scopes/output.txt | 2 +- acceptance/bundle/resources/apps/update-declared-scopes/script | 2 +- .../bundle/resources/apps/update-declared-scopes/test.toml | 1 - .../bundle/resources/apps/update-omitted-scopes/output.txt | 2 +- acceptance/bundle/resources/apps/update-omitted-scopes/script | 2 +- .../bundle/resources/apps/update-omitted-scopes/test.toml | 1 - 6 files changed, 4 insertions(+), 6 deletions(-) diff --git a/acceptance/bundle/resources/apps/update-declared-scopes/output.txt b/acceptance/bundle/resources/apps/update-declared-scopes/output.txt index 55553007373..efb4cabe0a0 100644 --- a/acceptance/bundle/resources/apps/update-declared-scopes/output.txt +++ b/acceptance/bundle/resources/apps/update-declared-scopes/output.txt @@ -6,7 +6,7 @@ Files: 2 uploaded, 0 deleted Resources: 1 created, 0 changed, 0 deleted, 0 unchanged === Out-of-band: add a scope the bundle cannot declare (e.g. via account-level update) ->>> [CLI] api post /api/2.0/apps/myappname/update --json {"app": {"name": "myappname", "user_api_scopes": ["sql", "files.files", "jobs"]}, "update_mask": "user_api_scopes"} +>>> MSYS_NO_PATHCONV=1 [CLI] api post /api/2.0/apps/myappname/update --json {"app": {"name": "myappname", "user_api_scopes": ["sql", "files.files", "jobs"]}, "update_mask": "user_api_scopes"} >>> [CLI] apps get myappname [ diff --git a/acceptance/bundle/resources/apps/update-declared-scopes/script b/acceptance/bundle/resources/apps/update-declared-scopes/script index 417375fb134..ae85a807d93 100644 --- a/acceptance/bundle/resources/apps/update-declared-scopes/script +++ b/acceptance/bundle/resources/apps/update-declared-scopes/script @@ -6,7 +6,7 @@ trace $CLI bundle deploy rm "$OUT_REQUESTS" title "Out-of-band: add a scope the bundle cannot declare (e.g. via account-level update)" -trace $CLI api post /api/2.0/apps/myappname/update --json '{"app": {"name": "myappname", "user_api_scopes": ["sql", "files.files", "jobs"]}, "update_mask": "user_api_scopes"}' > /dev/null +trace MSYS_NO_PATHCONV=1 $CLI api post /api/2.0/apps/myappname/update --json '{"app": {"name": "myappname", "user_api_scopes": ["sql", "files.files", "jobs"]}, "update_mask": "user_api_scopes"}' > /dev/null trace $CLI apps get myappname | jq .user_api_scopes rm "$OUT_REQUESTS" diff --git a/acceptance/bundle/resources/apps/update-declared-scopes/test.toml b/acceptance/bundle/resources/apps/update-declared-scopes/test.toml index b84ce38cae8..474ccd75b48 100644 --- a/acceptance/bundle/resources/apps/update-declared-scopes/test.toml +++ b/acceptance/bundle/resources/apps/update-declared-scopes/test.toml @@ -1,3 +1,2 @@ -Env.MSYS_NO_PATHCONV = "1" Cloud = false # jobs scope can only be added with account-admin privileges Ignore = [".databricks", "databricks.yml"] diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt b/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt index 5750de86368..131664e6e3f 100644 --- a/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/output.txt @@ -6,7 +6,7 @@ Files: 2 uploaded, 0 deleted Resources: 1 created, 0 changed, 0 deleted, 0 unchanged === Out-of-band: set scopes on an app whose bundle does not declare any ->>> [CLI] api post /api/2.0/apps/myappname/update --json {"app": {"name": "myappname", "user_api_scopes": ["sql", "jobs"]}, "update_mask": "user_api_scopes"} +>>> MSYS_NO_PATHCONV=1 [CLI] api post /api/2.0/apps/myappname/update --json {"app": {"name": "myappname", "user_api_scopes": ["sql", "jobs"]}, "update_mask": "user_api_scopes"} === Change description and re-deploy; user_api_scopes must not be in the update mask >>> update_file.py databricks.yml my_app_description MY_APP_DESCRIPTION diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/script b/acceptance/bundle/resources/apps/update-omitted-scopes/script index a57d5d8325f..db205b2fa4b 100644 --- a/acceptance/bundle/resources/apps/update-omitted-scopes/script +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/script @@ -6,7 +6,7 @@ trace $CLI bundle deploy rm "$OUT_REQUESTS" title "Out-of-band: set scopes on an app whose bundle does not declare any" -trace $CLI api post /api/2.0/apps/myappname/update --json '{"app": {"name": "myappname", "user_api_scopes": ["sql", "jobs"]}, "update_mask": "user_api_scopes"}' > /dev/null +trace MSYS_NO_PATHCONV=1 $CLI api post /api/2.0/apps/myappname/update --json '{"app": {"name": "myappname", "user_api_scopes": ["sql", "jobs"]}, "update_mask": "user_api_scopes"}' > /dev/null rm "$OUT_REQUESTS" title "Change description and re-deploy; user_api_scopes must not be in the update mask" diff --git a/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml b/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml index b84ce38cae8..474ccd75b48 100644 --- a/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml +++ b/acceptance/bundle/resources/apps/update-omitted-scopes/test.toml @@ -1,3 +1,2 @@ -Env.MSYS_NO_PATHCONV = "1" Cloud = false # jobs scope can only be added with account-admin privileges Ignore = [".databricks", "databricks.yml"]