From 23ac1f9b4edabf6cd707649648084496d06b6362 Mon Sep 17 00:00:00 2001 From: Rada Kamysheva Date: Thu, 23 Jul 2026 12:53:39 +0000 Subject: [PATCH 1/3] Fix spurious grants create for empty grants list on direct engine An empty grants: [] list produced no databricks_grants resource in terraform state, so bundle deployment migrate wrote no grants entry. The direct engine's makePlan then always emitted a plan node for the grants config node, so bundle plan showed a spurious 'create' for the empty grants node -- contradicting migrate's 'no actions planned'. Skip an empty grants node in makePlan when there is no existing state entry. When a state entry exists (grants were deployed and are now being emptied), the node is still emitted so the revoke is planned. --- .nextchanges/bundles/empty-grants-migrate.md | 1 + bundle/direct/bundle_plan.go | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 .nextchanges/bundles/empty-grants-migrate.md diff --git a/.nextchanges/bundles/empty-grants-migrate.md b/.nextchanges/bundles/empty-grants-migrate.md new file mode 100644 index 00000000000..121aa2b4c1f --- /dev/null +++ b/.nextchanges/bundles/empty-grants-migrate.md @@ -0,0 +1 @@ +Fixed the direct deployment engine planning a spurious `create` for a resource's empty `grants: []` list. An empty grants list with no existing state entry is now a no-op, so `bundle plan` reports no actions after `bundle deployment migrate` (Terraform never records a grants resource for an empty list). diff --git a/bundle/direct/bundle_plan.go b/bundle/direct/bundle_plan.go index 139012423ea..d074be52814 100644 --- a/bundle/direct/bundle_plan.go +++ b/bundle/direct/bundle_plan.go @@ -961,6 +961,19 @@ func (b *DeploymentBundle) makePlan(ctx context.Context, configRoot *config.Root if err != nil { return nil, err } + // An empty grants list with no state entry is a no-op: there is nothing + // to create and, unlike a non-empty-to-empty edit, no principals to revoke. + // Terraform never writes a databricks_grants resource for an empty list, so + // after "bundle deployment migrate" there is no state entry to match against; + // emitting a plan node here would show a spurious "create" and contradict + // migrate's promise of no actions planned. When a state entry does exist + // (grants were deployed and are now being emptied), keep the node so the + // revoke is still planned. + if gs, ok := inputConfigStructVar.Value.(*dresources.GrantsState); ok && len(gs.EmbeddedSlice) == 0 { + if _, hasState := db.State[node]; !hasState { + continue + } + } inputConfig = inputConfigStructVar.Value baseRefs = inputConfigStructVar.Refs } From e4d8d20adcea278ee4b7b01051847c17453a1667 Mon Sep 17 00:00:00 2001 From: Rada Kamysheva Date: Thu, 23 Jul 2026 13:01:53 +0000 Subject: [PATCH 2/3] Shorten comments in empty-grants fix --- bundle/direct/bundle_plan.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/bundle/direct/bundle_plan.go b/bundle/direct/bundle_plan.go index d074be52814..07ff3257588 100644 --- a/bundle/direct/bundle_plan.go +++ b/bundle/direct/bundle_plan.go @@ -961,14 +961,9 @@ func (b *DeploymentBundle) makePlan(ctx context.Context, configRoot *config.Root if err != nil { return nil, err } - // An empty grants list with no state entry is a no-op: there is nothing - // to create and, unlike a non-empty-to-empty edit, no principals to revoke. - // Terraform never writes a databricks_grants resource for an empty list, so - // after "bundle deployment migrate" there is no state entry to match against; - // emitting a plan node here would show a spurious "create" and contradict - // migrate's promise of no actions planned. When a state entry does exist - // (grants were deployed and are now being emptied), keep the node so the - // revoke is still planned. + // Terraform writes no grants resource for an empty list, so migrate leaves + // no state entry. Skip the node here too; otherwise plan shows a spurious + // "create". Keep it when state exists so emptying grants still revokes. if gs, ok := inputConfigStructVar.Value.(*dresources.GrantsState); ok && len(gs.EmbeddedSlice) == 0 { if _, hasState := db.State[node]; !hasState { continue From 5a47a082f2145f0943eaf7ba7121f64ad9ab731a Mon Sep 17 00:00:00 2001 From: Rada Kamysheva Date: Fri, 24 Jul 2026 07:31:02 +0000 Subject: [PATCH 3/3] acc: re-enable empty-grants invariant migrate variant With the direct-engine fix in place, the migrate invariant no longer shows a spurious grants -> create for an empty grants: [] list, so remove the no_empty_grants exclude added by the invariant-config PR and regenerate the migrate matrix. This is the variant the fuzz-found config was disabled for. --- acceptance/bundle/invariant/migrate/out.test.toml | 1 + acceptance/bundle/invariant/migrate/test.toml | 11 ----------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/acceptance/bundle/invariant/migrate/out.test.toml b/acceptance/bundle/invariant/migrate/out.test.toml index 0ac1b789d6f..469a1c81839 100644 --- a/acceptance/bundle/invariant/migrate/out.test.toml +++ b/acceptance/bundle/invariant/migrate/out.test.toml @@ -34,6 +34,7 @@ EnvMatrix.INPUT_CONFIG = [ "postgres_synced_table.yml.tmpl", "registered_model.yml.tmpl", "schema.yml.tmpl", + "schema_empty_grants.yml.tmpl", "schema_uppercase_name.yml.tmpl", "secret_scope.yml.tmpl", "secret_scope_default_backend_type.yml.tmpl", diff --git a/acceptance/bundle/invariant/migrate/test.toml b/acceptance/bundle/invariant/migrate/test.toml index 37dc2557922..a91f990df3b 100644 --- a/acceptance/bundle/invariant/migrate/test.toml +++ b/acceptance/bundle/invariant/migrate/test.toml @@ -26,17 +26,6 @@ EnvMatrixExclude.no_cross_resource_ref = ["INPUT_CONFIG=job_cross_resource_ref.y # Grant cross-references require the EmbeddedSlice pattern not present in terraform mode. EnvMatrixExclude.no_grant_ref = ["INPUT_CONFIG=schema_grant_ref.yml.tmpl"] -# An empty grants list plans a spurious create after migrate: Terraform records no -# databricks_grants resource for grants: [], so migrate leaves no state entry for the -# grants node, but the direct plan emits a "create" for it anyway. Found by fuzz testing. -# The plan check fails with: -# Unexpected action='create' for resources.schemas.foo.grants -# ... -# "resources.schemas.foo.grants": { "action": "create", ... } -# Exit code: 10 -# Fixed by https://github.com/databricks/cli/pull/6039; re-enable once that lands. -EnvMatrixExclude.no_empty_grants = ["INPUT_CONFIG=schema_empty_grants.yml.tmpl"] - # SQL warehouses currently failing with migration with permanent drift. TODO: fix this. EnvMatrixExclude.no_sql_warehouse = ["INPUT_CONFIG=sql_warehouse.yml.tmpl"]