Skip to content

Commit 1f437ff

Browse files
committed
Move secret scope .permissions handling from migrate.go to ParseResourcesState
ParseResourcesState now creates .permissions entries for ALL secret scopes (not just those with databricks_secret_acl), so the post-Apply fixup in migrate.go is no longer needed. Co-authored-by: Isaac
1 parent f315fa7 commit 1f437ff

File tree

3 files changed

+16
-40
lines changed

3 files changed

+16
-40
lines changed

bundle/deploy/terraform/util.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,20 @@ func parseResourcesState(ctx context.Context, path string) (ExportedResourcesMap
117117
}
118118
}
119119

120-
// Resolve secret scope permission IDs: use the scope name (which is the scope's ID)
121-
// instead of the Terraform ACL ID. The direct engine expects the scope name.
122-
for key := range result {
123-
if !strings.HasPrefix(key, "resources.secret_scopes.") || !strings.HasSuffix(key, ".permissions") {
120+
// Ensure every secret scope has a .permissions entry. The direct engine manages
121+
// permissions as a sub-resource (SecretScopeFixups adds MANAGE for the current user).
122+
// For scopes with databricks_secret_acl in state, resolve the ACL ID to the scope name.
123+
// For scopes without ACLs, create a .permissions entry with the scope name as ID.
124+
for key, entry := range result {
125+
if !strings.HasPrefix(key, "resources.secret_scopes.") || strings.Contains(key, ".permissions") {
124126
continue
125127
}
126-
scopeKey := strings.TrimSuffix(key, ".permissions")
127-
if scopeEntry, ok := result[scopeKey]; ok {
128-
result[key] = ResourceState{ID: scopeEntry.ID}
128+
permKey := key + ".permissions"
129+
if _, exists := result[permKey]; exists {
130+
// Resolve ACL ID → scope name (the direct engine expects scope name as ID).
131+
result[permKey] = ResourceState{ID: entry.ID}
132+
} else {
133+
result[permKey] = ResourceState{ID: entry.ID}
129134
}
130135
}
131136

bundle/deploy/terraform/util_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,10 @@ func TestParseResourcesStateSecretScopeWithoutAcls(t *testing.T) {
152152
state, err := parseResourcesState(ctx, path)
153153
require.NoError(t, err)
154154

155-
// No ACLs → no permissions entry; migrate.go fixup handles this case.
155+
// Even without ACLs, a .permissions entry is created for every secret scope,
156+
// so the direct engine doesn't plan a phantom "create" after migration.
156157
assert.Equal(t, ExportedResourcesMap{
157-
"resources.secret_scopes.my_scope": {ID: "my-scope-name"},
158+
"resources.secret_scopes.my_scope": {ID: "my-scope-name"},
159+
"resources.secret_scopes.my_scope.permissions": {ID: "my-scope-name"},
158160
}, state)
159161
}

cmd/bundle/deployment/migrate.go

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -281,37 +281,6 @@ To start using direct engine, set "engine: direct" under bundle in your databric
281281
return root.ErrAlreadyPrinted
282282
}
283283

284-
// Terraform manages secret scope permissions via databricks_secret_acl resources,
285-
// which are not included in the migration state. The direct engine manages them as
286-
// a sub-resource (secret_scopes.*.permissions). Add state entries so that the
287-
// direct engine doesn't plan a "create" action for these after migration.
288-
// This runs after Apply+Finalize, so we modify the in-memory state and re-save.
289-
needsResave := false
290-
for key := range deploymentBundle.StateDB.Data.State {
291-
if !strings.HasPrefix(key, "resources.secret_scopes.") || strings.HasSuffix(key, ".permissions") {
292-
continue
293-
}
294-
permKey := key + ".permissions"
295-
if _, exists := deploymentBundle.StateDB.Data.State[permKey]; exists {
296-
continue
297-
}
298-
entry := deploymentBundle.StateDB.Data.State[key]
299-
deploymentBundle.StateDB.Data.State[permKey] = dstate.ResourceEntry{
300-
ID: entry.ID,
301-
State: json.RawMessage("{}"),
302-
}
303-
needsResave = true
304-
}
305-
if needsResave {
306-
data, err := json.MarshalIndent(deploymentBundle.StateDB.Data, "", " ")
307-
if err != nil {
308-
return fmt.Errorf("failed to serialize state: %w", err)
309-
}
310-
if err := os.WriteFile(tempStatePath, data, 0o600); err != nil {
311-
return fmt.Errorf("failed to write state file: %w", err)
312-
}
313-
}
314-
315284
if err := os.Rename(tempStatePath, localPath); err != nil {
316285
return fmt.Errorf("renaming %s to %s: %w", tempStatePath, localPath, err)
317286
}

0 commit comments

Comments
 (0)