From 1cf595e92f9b1a3a73b55586aa190743f2fec7f3 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 23 Sep 2026 12:23:41 +0200 Subject: [PATCH 1/9] direct: make secrets remote mapping happen in DoRead/DoCreate/DoUpdate ResourceSecret's RemapState renamed effective_value/effective_owner to value/owner and dropped output-only fields. Move that into a shared remapSecretRemote helper applied wherever the remote is produced (DoRead/DoCreate/DoUpdate), so the remote is already mapped and RemapState becomes an identity no-op. Remove it; the adapter returns the remote unchanged. Plan remote_state now shows the mapped value/owner and omits output-only fields; the direct-only update-value golden is regenerated. Prep for replacing RemapState with the automatic copier. Co-authored-by: Isaac --- bundle/direct/dresources/secret.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/bundle/direct/dresources/secret.go b/bundle/direct/dresources/secret.go index 5e6e01b0f95..59696ec971b 100644 --- a/bundle/direct/dresources/secret.go +++ b/bundle/direct/dresources/secret.go @@ -45,7 +45,11 @@ func (*ResourceSecret) PrepareState(input *resources.Secret) *catalog.Secret { } } -func (*ResourceSecret) RemapState(remote *catalog.Secret) *catalog.Secret { +// remapSecretRemote maps a secret returned by the API to the config's shape: the resolved +// value and owner come back under effective_*, so we surface them under value/owner, and +// output-only fields are dropped. It runs wherever remote state is produced +// (DoRead/DoCreate/DoUpdate), so no RemapState hook is needed. +func remapSecretRemote(remote *catalog.Secret) *catalog.Secret { return &catalog.Secret{ CatalogName: remote.CatalogName, SchemaName: remote.SchemaName, @@ -66,14 +70,18 @@ func (*ResourceSecret) RemapState(remote *catalog.Secret) *catalog.Secret { } } -// DoRead fetches the secret by full name. IncludeValue is set so RemapState can +// DoRead fetches the secret by full name. IncludeValue is set so remapSecretRemote can // recover the stored value from EffectiveValue. func (r *ResourceSecret) DoRead(ctx context.Context, id string) (*catalog.Secret, error) { - return r.client.SecretsUc.GetSecret(ctx, catalog.GetSecretRequest{ + remote, err := r.client.SecretsUc.GetSecret(ctx, catalog.GetSecretRequest{ FullName: id, IncludeValue: true, ForceSendFields: nil, }) + if err != nil { + return nil, err + } + return remapSecretRemote(remote), nil } // DoCreate creates a new UC secret. @@ -84,7 +92,7 @@ func (r *ResourceSecret) DoCreate(ctx context.Context, state *catalog.Secret) (s if err != nil || response == nil { return "", nil, err } - return response.FullName, response, nil + return response.FullName, remapSecretRemote(response), nil } // comment is force-sent on update so that clearing it in config clears it on the secret. The @@ -106,7 +114,7 @@ func (r *ResourceSecret) DoUpdate(ctx context.Context, id string, state *catalog if err != nil { return nil, err } - return response, nil + return remapSecretRemote(response), nil } // DoDelete deletes the secret. From bf231885c7a58424ba1f4eba42e9c0549161e8f6 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 29 Sep 2026 13:18:50 +0200 Subject: [PATCH 2/9] acceptance: regenerate secrets/update-value golden for mapped remote_state Co-authored-by: Isaac --- .../bundle/resources/secrets/update-value/output.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/acceptance/bundle/resources/secrets/update-value/output.txt b/acceptance/bundle/resources/secrets/update-value/output.txt index 214af4d4c15..1487e12e66f 100644 --- a/acceptance/bundle/resources/secrets/update-value/output.txt +++ b/acceptance/bundle/resources/secrets/update-value/output.txt @@ -61,17 +61,9 @@ secrets secret1 catalog_name='main' schema_name='default' name='test_secret' com "remote_state": { "catalog_name": "main", "comment": "Test secret", - "create_time": "[TIMESTAMP]", - "created_by": "[USERNAME]", - "effective_owner": "[USERNAME]", - "effective_value": "[redacted]", - "full_name": "main.default.test_secret", - "metastore_id": "test-metastore-id", "name": "test_secret", "owner": "[USERNAME]", "schema_name": "default", - "update_time": "[TIMESTAMP]", - "updated_by": "[USERNAME]", "value": "[redacted]" }, "changes": { From fc7ac259c1718dfb5e4a5725beda09254e751d5a Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Tue, 29 Sep 2026 18:49:28 +0200 Subject: [PATCH 3/9] direct: drop the redundant secrets RemapState instead of reshaping the remote StateType and RemoteType are both catalog.Secret, and every field the old RemapState reshaped is already declared ignore_remote_changes (value/owner are input_only; create_time, effective_value, metastore_id, etc. are output_only). The reshape suppressed no drift; it only discarded the output-only fields from the plan's remote_state display. Removing it: DoRead/DoCreate/DoUpdate already return the raw secret, the field classifications handle drift, and the full remote is visible again. Co-authored-by: Isaac --- .../remove-expire-time/out.plan.direct.json | 45 +++++++++++++++-- .../out.plan.drift.direct.json | 45 +++++++++++++++-- .../update-expire-time/out.plan.direct.json | 45 +++++++++++++++-- .../resources/secrets/update-value/output.txt | 50 ++++++++++++++++++- bundle/direct/dresources/secret.go | 40 +++------------ 5 files changed, 181 insertions(+), 44 deletions(-) diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json index a3722f74ae4..fb34a0d8159 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json @@ -1,22 +1,61 @@ { "action": "update", "changes": { + "create_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "created_by": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "effective_owner": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "effective_value": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[redacted]" + }, "expire_time": { "action": "update", "old": "[EXPIRE_TIME_BEFORE]", "remote": "[EXPIRE_TIME_BEFORE]" }, + "full_name": { + "action": "skip", + "reason": "spec:output_only", + "remote": "main.default.test_secret_[UNIQUE_NAME]" + }, + "metastore_id": { + "action": "skip", + "reason": "spec:output_only", + "remote": "test-metastore-id" + }, "owner": { "action": "skip", "reason": "spec:input_only", "remote": "[USERNAME]" }, - "value": { + "update_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "updated_by": { "action": "skip", - "reason": "custom", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "value": { + "action": "update", "old": "", "new": "[redacted]", - "remote": "[redacted]" + "remote": "" } } } diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json index c42ccac5651..103e53dc447 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json @@ -1,21 +1,60 @@ { "action": "update", "changes": { + "create_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "created_by": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "effective_owner": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "effective_value": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[redacted]" + }, "expire_time": { "action": "update", "remote": "[EXPIRE_TIME_BEFORE]" }, + "full_name": { + "action": "skip", + "reason": "spec:output_only", + "remote": "main.default.test_secret_[UNIQUE_NAME]" + }, + "metastore_id": { + "action": "skip", + "reason": "spec:output_only", + "remote": "test-metastore-id" + }, "owner": { "action": "skip", "reason": "spec:input_only", "remote": "[USERNAME]" }, - "value": { + "update_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "updated_by": { "action": "skip", - "reason": "custom", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "value": { + "action": "update", "old": "", "new": "[redacted]", - "remote": "[redacted]" + "remote": "" } } } diff --git a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json index 2da131f5384..f9af435a228 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json @@ -1,23 +1,62 @@ { "action": "update", "changes": { + "create_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "created_by": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "effective_owner": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "effective_value": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[redacted]" + }, "expire_time": { "action": "update", "old": "[EXPIRE_TIME_BEFORE]", "new": "[EXPIRE_TIME_AFTER]", "remote": "[EXPIRE_TIME_BEFORE]" }, + "full_name": { + "action": "skip", + "reason": "spec:output_only", + "remote": "main.default.test_secret_[UNIQUE_NAME]" + }, + "metastore_id": { + "action": "skip", + "reason": "spec:output_only", + "remote": "test-metastore-id" + }, "owner": { "action": "skip", "reason": "spec:input_only", "remote": "[USERNAME]" }, - "value": { + "update_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "updated_by": { "action": "skip", - "reason": "custom", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "value": { + "action": "update", "old": "", "new": "[redacted]", - "remote": "[redacted]" + "remote": "" } } } diff --git a/acceptance/bundle/resources/secrets/update-value/output.txt b/acceptance/bundle/resources/secrets/update-value/output.txt index 1487e12e66f..669ae5c08c2 100644 --- a/acceptance/bundle/resources/secrets/update-value/output.txt +++ b/acceptance/bundle/resources/secrets/update-value/output.txt @@ -61,22 +61,70 @@ secrets secret1 catalog_name='main' schema_name='default' name='test_secret' com "remote_state": { "catalog_name": "main", "comment": "Test secret", + "create_time": "[TIMESTAMP]", + "created_by": "[USERNAME]", + "effective_owner": "[USERNAME]", + "effective_value": "[redacted]", + "full_name": "main.default.test_secret", + "metastore_id": "test-metastore-id", "name": "test_secret", "owner": "[USERNAME]", "schema_name": "default", + "update_time": "[TIMESTAMP]", + "updated_by": "[USERNAME]", "value": "[redacted]" }, "changes": { + "create_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "created_by": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "effective_owner": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, + "effective_value": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[redacted]" + }, + "full_name": { + "action": "skip", + "reason": "spec:output_only", + "remote": "main.default.test_secret" + }, + "metastore_id": { + "action": "skip", + "reason": "spec:output_only", + "remote": "test-metastore-id" + }, "owner": { "action": "skip", "reason": "spec:input_only", "remote": "[USERNAME]" }, + "update_time": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[TIMESTAMP]" + }, + "updated_by": { + "action": "skip", + "reason": "spec:output_only", + "remote": "[USERNAME]" + }, "value": { "action": "update", "old": "", "new": "[redacted]", - "remote": "[redacted]" + "remote": "" } } } diff --git a/bundle/direct/dresources/secret.go b/bundle/direct/dresources/secret.go index 59696ec971b..b433d24e2f0 100644 --- a/bundle/direct/dresources/secret.go +++ b/bundle/direct/dresources/secret.go @@ -45,43 +45,15 @@ func (*ResourceSecret) PrepareState(input *resources.Secret) *catalog.Secret { } } -// remapSecretRemote maps a secret returned by the API to the config's shape: the resolved -// value and owner come back under effective_*, so we surface them under value/owner, and -// output-only fields are dropped. It runs wherever remote state is produced -// (DoRead/DoCreate/DoUpdate), so no RemapState hook is needed. -func remapSecretRemote(remote *catalog.Secret) *catalog.Secret { - return &catalog.Secret{ - CatalogName: remote.CatalogName, - SchemaName: remote.SchemaName, - Name: remote.Name, - Value: remote.EffectiveValue, - Comment: remote.Comment, - ExpireTime: remote.ExpireTime, - Owner: remote.EffectiveOwner, - CreateTime: nil, - CreatedBy: "", - EffectiveOwner: "", - EffectiveValue: "", - FullName: "", - MetastoreId: "", - UpdateTime: nil, - UpdatedBy: "", - ForceSendFields: utils.FilterFields[catalog.Secret](nil), - } -} - -// DoRead fetches the secret by full name. IncludeValue is set so remapSecretRemote can -// recover the stored value from EffectiveValue. +// DoRead fetches the secret by full name. IncludeValue is set so effective_value carries +// the stored value; value/owner and the output-only metadata are declared +// ignore_remote_changes, so the full remote can flow through unchanged. func (r *ResourceSecret) DoRead(ctx context.Context, id string) (*catalog.Secret, error) { - remote, err := r.client.SecretsUc.GetSecret(ctx, catalog.GetSecretRequest{ + return r.client.SecretsUc.GetSecret(ctx, catalog.GetSecretRequest{ FullName: id, IncludeValue: true, ForceSendFields: nil, }) - if err != nil { - return nil, err - } - return remapSecretRemote(remote), nil } // DoCreate creates a new UC secret. @@ -92,7 +64,7 @@ func (r *ResourceSecret) DoCreate(ctx context.Context, state *catalog.Secret) (s if err != nil || response == nil { return "", nil, err } - return response.FullName, remapSecretRemote(response), nil + return response.FullName, response, nil } // comment is force-sent on update so that clearing it in config clears it on the secret. The @@ -114,7 +86,7 @@ func (r *ResourceSecret) DoUpdate(ctx context.Context, id string, state *catalog if err != nil { return nil, err } - return remapSecretRemote(response), nil + return response, nil } // DoDelete deletes the secret. From 08a1f6f1285bb4397e55dcbeb308e99e493e5a27 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 30 Sep 2026 07:58:54 +0200 Subject: [PATCH 4/9] direct: map secrets value/owner in place; keep the output-only fields remapSecretRemote now sets value/owner from the effective_* fields the API returns (so persisted state matches config and re-plans show no drift) but leaves the output-only metadata (create_time, effective_value, metastore_id, ...) intact for the plan's remote_state display. Replaces the old RemapState, which zeroed those fields and thus dropped them from the display. Verified against the invariant no_drift suite. Co-authored-by: Isaac --- .../remove-expire-time/out.plan.direct.json | 5 ++-- .../out.plan.drift.direct.json | 5 ++-- .../update-expire-time/out.plan.direct.json | 5 ++-- .../resources/secrets/update-value/output.txt | 2 +- bundle/direct/dresources/secret.go | 27 ++++++++++++++----- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json index fb34a0d8159..c0205267eef 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json @@ -52,10 +52,11 @@ "remote": "[USERNAME]" }, "value": { - "action": "update", + "action": "skip", + "reason": "custom", "old": "", "new": "[redacted]", - "remote": "" + "remote": "[redacted]" } } } diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json index 103e53dc447..542088cc7e9 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json @@ -51,10 +51,11 @@ "remote": "[USERNAME]" }, "value": { - "action": "update", + "action": "skip", + "reason": "custom", "old": "", "new": "[redacted]", - "remote": "" + "remote": "[redacted]" } } } diff --git a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json index f9af435a228..0c25f251550 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json @@ -53,10 +53,11 @@ "remote": "[USERNAME]" }, "value": { - "action": "update", + "action": "skip", + "reason": "custom", "old": "", "new": "[redacted]", - "remote": "" + "remote": "[redacted]" } } } diff --git a/acceptance/bundle/resources/secrets/update-value/output.txt b/acceptance/bundle/resources/secrets/update-value/output.txt index 669ae5c08c2..8f12f1e007a 100644 --- a/acceptance/bundle/resources/secrets/update-value/output.txt +++ b/acceptance/bundle/resources/secrets/update-value/output.txt @@ -124,7 +124,7 @@ secrets secret1 catalog_name='main' schema_name='default' name='test_secret' com "action": "update", "old": "", "new": "[redacted]", - "remote": "" + "remote": "[redacted]" } } } diff --git a/bundle/direct/dresources/secret.go b/bundle/direct/dresources/secret.go index b433d24e2f0..2db0a334f82 100644 --- a/bundle/direct/dresources/secret.go +++ b/bundle/direct/dresources/secret.go @@ -45,15 +45,30 @@ func (*ResourceSecret) PrepareState(input *resources.Secret) *catalog.Secret { } } -// DoRead fetches the secret by full name. IncludeValue is set so effective_value carries -// the stored value; value/owner and the output-only metadata are declared -// ignore_remote_changes, so the full remote can flow through unchanged. +// remapSecretRemote surfaces the resolved value and owner (the API returns them under +// effective_value/effective_owner) under value/owner so remote state matches the config +// shape — without this, the persisted value is empty and every plan re-reports an update. +// The rest of the secret, including the output-only metadata, is left intact and handled +// by ignore_remote_changes, so no information is discarded. It runs wherever remote state +// is produced (DoRead/DoCreate/DoUpdate), so no RemapState hook is needed. +func remapSecretRemote(remote *catalog.Secret) *catalog.Secret { + remote.Value = remote.EffectiveValue + remote.Owner = remote.EffectiveOwner + return remote +} + +// DoRead fetches the secret by full name. IncludeValue is set so remapSecretRemote can +// recover the stored value from EffectiveValue. func (r *ResourceSecret) DoRead(ctx context.Context, id string) (*catalog.Secret, error) { - return r.client.SecretsUc.GetSecret(ctx, catalog.GetSecretRequest{ + remote, err := r.client.SecretsUc.GetSecret(ctx, catalog.GetSecretRequest{ FullName: id, IncludeValue: true, ForceSendFields: nil, }) + if err != nil { + return nil, err + } + return remapSecretRemote(remote), nil } // DoCreate creates a new UC secret. @@ -64,7 +79,7 @@ func (r *ResourceSecret) DoCreate(ctx context.Context, state *catalog.Secret) (s if err != nil || response == nil { return "", nil, err } - return response.FullName, response, nil + return response.FullName, remapSecretRemote(response), nil } // comment is force-sent on update so that clearing it in config clears it on the secret. The @@ -86,7 +101,7 @@ func (r *ResourceSecret) DoUpdate(ctx context.Context, id string, state *catalog if err != nil { return nil, err } - return response, nil + return remapSecretRemote(response), nil } // DoDelete deletes the secret. From 4161602dac7148db661399d3cb4e388372f67a2b Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 30 Sep 2026 10:24:25 +0200 Subject: [PATCH 5/9] acceptance: normalize secrets metastore_id for cloud runs Keeping the output-only fields means metastore_id now appears in the plan. It is a fixed testserver literal locally but a real UUID on cloud, which broke the Cloud=true update-expire-time/remove-expire-time integration runs. Add [METASTORE_ID] replacements (literal + UUID regex, Order=-1) scoped to those two tests so the golden is stable across environments. Co-authored-by: Isaac --- .../secrets/remove-expire-time/out.plan.direct.json | 2 +- .../remove-expire-time/out.plan.drift.direct.json | 2 +- .../resources/secrets/remove-expire-time/test.toml | 13 +++++++++++++ .../secrets/update-expire-time/out.plan.direct.json | 2 +- .../resources/secrets/update-expire-time/test.toml | 13 +++++++++++++ 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json index c0205267eef..3fe1211baaf 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json @@ -34,7 +34,7 @@ "metastore_id": { "action": "skip", "reason": "spec:output_only", - "remote": "test-metastore-id" + "remote": "[METASTORE_ID]" }, "owner": { "action": "skip", diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json index 542088cc7e9..eca9079401c 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json @@ -33,7 +33,7 @@ "metastore_id": { "action": "skip", "reason": "spec:output_only", - "remote": "test-metastore-id" + "remote": "[METASTORE_ID]" }, "owner": { "action": "skip", diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/test.toml b/acceptance/bundle/resources/secrets/remove-expire-time/test.toml index fd26f5c84d1..46c8660b203 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/test.toml +++ b/acceptance/bundle/resources/secrets/remove-expire-time/test.toml @@ -23,3 +23,16 @@ Badness = "Removing expire_time never takes effect: the API keeps the previous v Old = '2030-01-01T00:00:00Z' New = '[EXPIRE_TIME_BEFORE]' Order = 1 + +# metastore_id is a workspace-global UUID: a fixed testserver literal locally, a real UUID on +# cloud. Normalize both so the plan golden is stable across environments. Order below the root +# numeric rules (default 0) so a cloud UUID is captured whole before digit-run rules nibble it. +[[Repls]] +Old = 'test-metastore-id' +New = '[METASTORE_ID]' +Order = -1 + +[[Repls]] +Old = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' +New = '[METASTORE_ID]' +Order = -1 diff --git a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json index 0c25f251550..d0da086de2b 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json @@ -35,7 +35,7 @@ "metastore_id": { "action": "skip", "reason": "spec:output_only", - "remote": "test-metastore-id" + "remote": "[METASTORE_ID]" }, "owner": { "action": "skip", diff --git a/acceptance/bundle/resources/secrets/update-expire-time/test.toml b/acceptance/bundle/resources/secrets/update-expire-time/test.toml index dda317530a6..b0c958b87f5 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/test.toml +++ b/acceptance/bundle/resources/secrets/update-expire-time/test.toml @@ -21,3 +21,16 @@ Order = 1 Old = '2031-06-15T12:00:00Z' New = '[EXPIRE_TIME_AFTER]' Order = 1 + +# metastore_id is a workspace-global UUID: a fixed testserver literal locally, a real UUID on +# cloud. Normalize both so the plan golden is stable across environments. Order below the root +# numeric rules (default 0) so a cloud UUID is captured whole before digit-run rules nibble it. +[[Repls]] +Old = 'test-metastore-id' +New = '[METASTORE_ID]' +Order = -1 + +[[Repls]] +Old = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' +New = '[METASTORE_ID]' +Order = -1 From 0be474c0f35bb68942780f723bd437f2a3622e16 Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 30 Sep 2026 11:08:56 +0200 Subject: [PATCH 6/9] acceptance: normalize secrets metastore_id via runtime add_repl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bare UUID regex over-matched the cloud service-principal username in the workspace path (/Workspace/Users/ -> [METASTORE_ID] instead of [USERNAME]). Instead, extract the exact metastore_id from the plan and add_repl it: a literal match at Order -100 that normalizes only that value to [METASTORE_ID] — the testserver literal locally and the real UUID on cloud — before the numeric rules run, without touching usernames. Co-authored-by: Isaac --- .../resources/secrets/remove-expire-time/script | 3 +++ .../resources/secrets/remove-expire-time/test.toml | 13 ------------- .../resources/secrets/update-expire-time/script | 3 +++ .../resources/secrets/update-expire-time/test.toml | 13 ------------- 4 files changed, 6 insertions(+), 26 deletions(-) diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/script b/acceptance/bundle/resources/secrets/remove-expire-time/script index 1659dfb2fee..09ad970fab6 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/script +++ b/acceptance/bundle/resources/secrets/remove-expire-time/script @@ -14,6 +14,9 @@ title "Remove expire_time and re-deploy" trace update_file.py databricks.yml ' expire_time: "2030-01-01T00:00:00Z"' "" trace $CLI bundle plan --var secret_value=secret-value trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json +# metastore_id is a workspace-global UUID (a fixed literal on the testserver, a real UUID on +# cloud); replace its exact value so the plan golden is stable across environments. +add_repl "$(jq -r '.changes.metastore_id.remote' out.plan.$DATABRICKS_BUNDLE_ENGINE.json)" METASTORE_ID trace $CLI bundle deploy --var secret_value=secret-value trace print_requests.py //unity-catalog read_state.py secrets secret1 name expire_time diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/test.toml b/acceptance/bundle/resources/secrets/remove-expire-time/test.toml index 46c8660b203..fd26f5c84d1 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/test.toml +++ b/acceptance/bundle/resources/secrets/remove-expire-time/test.toml @@ -23,16 +23,3 @@ Badness = "Removing expire_time never takes effect: the API keeps the previous v Old = '2030-01-01T00:00:00Z' New = '[EXPIRE_TIME_BEFORE]' Order = 1 - -# metastore_id is a workspace-global UUID: a fixed testserver literal locally, a real UUID on -# cloud. Normalize both so the plan golden is stable across environments. Order below the root -# numeric rules (default 0) so a cloud UUID is captured whole before digit-run rules nibble it. -[[Repls]] -Old = 'test-metastore-id' -New = '[METASTORE_ID]' -Order = -1 - -[[Repls]] -Old = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' -New = '[METASTORE_ID]' -Order = -1 diff --git a/acceptance/bundle/resources/secrets/update-expire-time/script b/acceptance/bundle/resources/secrets/update-expire-time/script index fe58d8c30c0..1fb449db38c 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/script +++ b/acceptance/bundle/resources/secrets/update-expire-time/script @@ -14,6 +14,9 @@ title "Change expire_time and re-deploy" trace update_file.py databricks.yml "2030-01-01T00:00:00Z" "2031-06-15T12:00:00Z" trace $CLI bundle plan --var secret_value=secret-value trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json +# metastore_id is a workspace-global UUID (a fixed literal on the testserver, a real UUID on +# cloud); replace its exact value so the plan golden is stable across environments. +add_repl "$(jq -r '.changes.metastore_id.remote' out.plan.$DATABRICKS_BUNDLE_ENGINE.json)" METASTORE_ID trace $CLI bundle deploy --var secret_value=secret-value trace print_requests.py //unity-catalog read_state.py secrets secret1 name expire_time diff --git a/acceptance/bundle/resources/secrets/update-expire-time/test.toml b/acceptance/bundle/resources/secrets/update-expire-time/test.toml index b0c958b87f5..dda317530a6 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/test.toml +++ b/acceptance/bundle/resources/secrets/update-expire-time/test.toml @@ -21,16 +21,3 @@ Order = 1 Old = '2031-06-15T12:00:00Z' New = '[EXPIRE_TIME_AFTER]' Order = 1 - -# metastore_id is a workspace-global UUID: a fixed testserver literal locally, a real UUID on -# cloud. Normalize both so the plan golden is stable across environments. Order below the root -# numeric rules (default 0) so a cloud UUID is captured whole before digit-run rules nibble it. -[[Repls]] -Old = 'test-metastore-id' -New = '[METASTORE_ID]' -Order = -1 - -[[Repls]] -Old = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' -New = '[METASTORE_ID]' -Order = -1 From eb26cf4b982f6efab1c9468e3e6e662402cce5db Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 30 Sep 2026 11:43:57 +0200 Subject: [PATCH 7/9] acceptance: project secrets expire-time plans to the asserted field Keeping the output-only fields drags them into the plan's changes set, and their remote values differ between the testserver and a real workspace (metastore_id, comment, timestamps), which broke the Cloud runs. Project the update-expire-time/remove-expire-time plans to expire_time -- the field these tests assert -- per the allow-list rule in testing.md. This drops the earlier per-field metastore_id add_repl and fixes the remaining comment mismatch in one move; update-value still shows the full remote_state. Co-authored-by: Isaac --- .../remove-expire-time/out.plan.direct.json | 52 ------------------- .../out.plan.drift.direct.json | 52 ------------------- .../secrets/remove-expire-time/script | 10 ++-- .../update-expire-time/out.plan.direct.json | 52 ------------------- .../secrets/update-expire-time/script | 8 +-- 5 files changed, 9 insertions(+), 165 deletions(-) diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json index 3fe1211baaf..25fe0dfdd21 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json @@ -1,62 +1,10 @@ { "action": "update", "changes": { - "create_time": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[TIMESTAMP]" - }, - "created_by": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[USERNAME]" - }, - "effective_owner": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[USERNAME]" - }, - "effective_value": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[redacted]" - }, "expire_time": { "action": "update", "old": "[EXPIRE_TIME_BEFORE]", "remote": "[EXPIRE_TIME_BEFORE]" - }, - "full_name": { - "action": "skip", - "reason": "spec:output_only", - "remote": "main.default.test_secret_[UNIQUE_NAME]" - }, - "metastore_id": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[METASTORE_ID]" - }, - "owner": { - "action": "skip", - "reason": "spec:input_only", - "remote": "[USERNAME]" - }, - "update_time": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[TIMESTAMP]" - }, - "updated_by": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[USERNAME]" - }, - "value": { - "action": "skip", - "reason": "custom", - "old": "", - "new": "[redacted]", - "remote": "[redacted]" } } } diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json index eca9079401c..b1fee9b1dff 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json @@ -1,61 +1,9 @@ { "action": "update", "changes": { - "create_time": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[TIMESTAMP]" - }, - "created_by": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[USERNAME]" - }, - "effective_owner": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[USERNAME]" - }, - "effective_value": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[redacted]" - }, "expire_time": { "action": "update", "remote": "[EXPIRE_TIME_BEFORE]" - }, - "full_name": { - "action": "skip", - "reason": "spec:output_only", - "remote": "main.default.test_secret_[UNIQUE_NAME]" - }, - "metastore_id": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[METASTORE_ID]" - }, - "owner": { - "action": "skip", - "reason": "spec:input_only", - "remote": "[USERNAME]" - }, - "update_time": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[TIMESTAMP]" - }, - "updated_by": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[USERNAME]" - }, - "value": { - "action": "skip", - "reason": "custom", - "old": "", - "new": "[redacted]", - "remote": "[redacted]" } } } diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/script b/acceptance/bundle/resources/secrets/remove-expire-time/script index 09ad970fab6..f0f0c532ff9 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/script +++ b/acceptance/bundle/resources/secrets/remove-expire-time/script @@ -13,16 +13,16 @@ read_state.py secrets secret1 name expire_time title "Remove expire_time and re-deploy" trace update_file.py databricks.yml ' expire_time: "2030-01-01T00:00:00Z"' "" trace $CLI bundle plan --var secret_value=secret-value -trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json -# metastore_id is a workspace-global UUID (a fixed literal on the testserver, a real UUID on -# cloud); replace its exact value so the plan golden is stable across environments. -add_repl "$(jq -r '.changes.metastore_id.remote' out.plan.$DATABRICKS_BUNDLE_ENGINE.json)" METASTORE_ID +# Project to expire_time (the field this test is about): the full changes set now carries +# output-only fields whose remote values differ between the testserver and a real workspace +# (metastore_id, comment, timestamps), which is noise here and breaks the Cloud run. +trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json trace $CLI bundle deploy --var secret_value=secret-value trace print_requests.py //unity-catalog read_state.py secrets secret1 name expire_time title "Plan again to record any drift the removal leaves behind" trace $CLI bundle plan --var secret_value=secret-value -trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes}' > out.plan.drift.$DATABRICKS_BUNDLE_ENGINE.json +trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time})}' > out.plan.drift.$DATABRICKS_BUNDLE_ENGINE.json rm -f "$OUT_REQUESTS" diff --git a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json index d0da086de2b..e35c1cf5e46 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json @@ -1,63 +1,11 @@ { "action": "update", "changes": { - "create_time": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[TIMESTAMP]" - }, - "created_by": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[USERNAME]" - }, - "effective_owner": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[USERNAME]" - }, - "effective_value": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[redacted]" - }, "expire_time": { "action": "update", "old": "[EXPIRE_TIME_BEFORE]", "new": "[EXPIRE_TIME_AFTER]", "remote": "[EXPIRE_TIME_BEFORE]" - }, - "full_name": { - "action": "skip", - "reason": "spec:output_only", - "remote": "main.default.test_secret_[UNIQUE_NAME]" - }, - "metastore_id": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[METASTORE_ID]" - }, - "owner": { - "action": "skip", - "reason": "spec:input_only", - "remote": "[USERNAME]" - }, - "update_time": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[TIMESTAMP]" - }, - "updated_by": { - "action": "skip", - "reason": "spec:output_only", - "remote": "[USERNAME]" - }, - "value": { - "action": "skip", - "reason": "custom", - "old": "", - "new": "[redacted]", - "remote": "[redacted]" } } } diff --git a/acceptance/bundle/resources/secrets/update-expire-time/script b/acceptance/bundle/resources/secrets/update-expire-time/script index 1fb449db38c..b8a9732e4a0 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/script +++ b/acceptance/bundle/resources/secrets/update-expire-time/script @@ -13,10 +13,10 @@ read_state.py secrets secret1 name expire_time title "Change expire_time and re-deploy" trace update_file.py databricks.yml "2030-01-01T00:00:00Z" "2031-06-15T12:00:00Z" trace $CLI bundle plan --var secret_value=secret-value -trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json -# metastore_id is a workspace-global UUID (a fixed literal on the testserver, a real UUID on -# cloud); replace its exact value so the plan golden is stable across environments. -add_repl "$(jq -r '.changes.metastore_id.remote' out.plan.$DATABRICKS_BUNDLE_ENGINE.json)" METASTORE_ID +# Project to expire_time (the field this test is about): the full changes set now carries +# output-only fields whose remote values differ between the testserver and a real workspace +# (metastore_id, comment, timestamps), which is noise here and breaks the Cloud run. +trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json trace $CLI bundle deploy --var secret_value=secret-value trace print_requests.py //unity-catalog read_state.py secrets secret1 name expire_time From 57fdbc86b7d66e06718534561c11290d44d11cea Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 30 Sep 2026 13:00:20 +0200 Subject: [PATCH 8/9] acceptance: keep value/owner in secrets expire-time plans The earlier projection to {expire_time} dropped value/owner as collateral, though they normalize cleanly on cloud ([redacted]/[USERNAME]) and aren't a fidelity risk. Project to {expire_time, value, owner} instead -- keeping those while still excluding the fidelity-sensitive output-only fields (metastore_id, comment, timestamps). Co-authored-by: Isaac --- .../secrets/remove-expire-time/out.plan.direct.json | 12 ++++++++++++ .../remove-expire-time/out.plan.drift.direct.json | 12 ++++++++++++ .../resources/secrets/remove-expire-time/script | 4 ++-- .../secrets/update-expire-time/out.plan.direct.json | 12 ++++++++++++ .../resources/secrets/update-expire-time/script | 2 +- 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json index 25fe0dfdd21..eaff6aad3a9 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json @@ -5,6 +5,18 @@ "action": "update", "old": "[EXPIRE_TIME_BEFORE]", "remote": "[EXPIRE_TIME_BEFORE]" + }, + "value": { + "action": "skip", + "reason": "custom", + "old": "", + "new": "[redacted]", + "remote": "[redacted]" + }, + "owner": { + "action": "skip", + "reason": "spec:input_only", + "remote": "[USERNAME]" } } } diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json index b1fee9b1dff..580d862c606 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json @@ -4,6 +4,18 @@ "expire_time": { "action": "update", "remote": "[EXPIRE_TIME_BEFORE]" + }, + "value": { + "action": "skip", + "reason": "custom", + "old": "", + "new": "[redacted]", + "remote": "[redacted]" + }, + "owner": { + "action": "skip", + "reason": "spec:input_only", + "remote": "[USERNAME]" } } } diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/script b/acceptance/bundle/resources/secrets/remove-expire-time/script index f0f0c532ff9..e93735bd593 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/script +++ b/acceptance/bundle/resources/secrets/remove-expire-time/script @@ -16,13 +16,13 @@ trace $CLI bundle plan --var secret_value=secret-value # Project to expire_time (the field this test is about): the full changes set now carries # output-only fields whose remote values differ between the testserver and a real workspace # (metastore_id, comment, timestamps), which is noise here and breaks the Cloud run. -trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json +trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time, value, owner})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json trace $CLI bundle deploy --var secret_value=secret-value trace print_requests.py //unity-catalog read_state.py secrets secret1 name expire_time title "Plan again to record any drift the removal leaves behind" trace $CLI bundle plan --var secret_value=secret-value -trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time})}' > out.plan.drift.$DATABRICKS_BUNDLE_ENGINE.json +trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time, value, owner})}' > out.plan.drift.$DATABRICKS_BUNDLE_ENGINE.json rm -f "$OUT_REQUESTS" diff --git a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json index e35c1cf5e46..2e72f38b765 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json @@ -6,6 +6,18 @@ "old": "[EXPIRE_TIME_BEFORE]", "new": "[EXPIRE_TIME_AFTER]", "remote": "[EXPIRE_TIME_BEFORE]" + }, + "value": { + "action": "skip", + "reason": "custom", + "old": "", + "new": "[redacted]", + "remote": "[redacted]" + }, + "owner": { + "action": "skip", + "reason": "spec:input_only", + "remote": "[USERNAME]" } } } diff --git a/acceptance/bundle/resources/secrets/update-expire-time/script b/acceptance/bundle/resources/secrets/update-expire-time/script index b8a9732e4a0..7f32addde27 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/script +++ b/acceptance/bundle/resources/secrets/update-expire-time/script @@ -16,7 +16,7 @@ trace $CLI bundle plan --var secret_value=secret-value # Project to expire_time (the field this test is about): the full changes set now carries # output-only fields whose remote values differ between the testserver and a real workspace # (metastore_id, comment, timestamps), which is noise here and breaks the Cloud run. -trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json +trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time, value, owner})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json trace $CLI bundle deploy --var secret_value=secret-value trace print_requests.py //unity-catalog read_state.py secrets secret1 name expire_time From c46408b2b92cafdeb95cb36cc54c5d3ad2e4d5ff Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Wed, 30 Sep 2026 13:30:52 +0200 Subject: [PATCH 9/9] acceptance: keep the plan's natural field order in secrets expire-time projections jq object construction emits keys in the order listed, so {expire_time, value, owner} put value before owner. The plan's natural order is alphabetical (owner < value), so list {expire_time, owner, value} to match and avoid reordering the golden. Co-authored-by: Isaac --- .../secrets/remove-expire-time/out.plan.direct.json | 10 +++++----- .../remove-expire-time/out.plan.drift.direct.json | 10 +++++----- .../bundle/resources/secrets/remove-expire-time/script | 4 ++-- .../secrets/update-expire-time/out.plan.direct.json | 10 +++++----- .../bundle/resources/secrets/update-expire-time/script | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json index eaff6aad3a9..a3722f74ae4 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.direct.json @@ -6,17 +6,17 @@ "old": "[EXPIRE_TIME_BEFORE]", "remote": "[EXPIRE_TIME_BEFORE]" }, + "owner": { + "action": "skip", + "reason": "spec:input_only", + "remote": "[USERNAME]" + }, "value": { "action": "skip", "reason": "custom", "old": "", "new": "[redacted]", "remote": "[redacted]" - }, - "owner": { - "action": "skip", - "reason": "spec:input_only", - "remote": "[USERNAME]" } } } diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json index 580d862c606..c42ccac5651 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json +++ b/acceptance/bundle/resources/secrets/remove-expire-time/out.plan.drift.direct.json @@ -5,17 +5,17 @@ "action": "update", "remote": "[EXPIRE_TIME_BEFORE]" }, + "owner": { + "action": "skip", + "reason": "spec:input_only", + "remote": "[USERNAME]" + }, "value": { "action": "skip", "reason": "custom", "old": "", "new": "[redacted]", "remote": "[redacted]" - }, - "owner": { - "action": "skip", - "reason": "spec:input_only", - "remote": "[USERNAME]" } } } diff --git a/acceptance/bundle/resources/secrets/remove-expire-time/script b/acceptance/bundle/resources/secrets/remove-expire-time/script index e93735bd593..d22f67aa06b 100644 --- a/acceptance/bundle/resources/secrets/remove-expire-time/script +++ b/acceptance/bundle/resources/secrets/remove-expire-time/script @@ -16,13 +16,13 @@ trace $CLI bundle plan --var secret_value=secret-value # Project to expire_time (the field this test is about): the full changes set now carries # output-only fields whose remote values differ between the testserver and a real workspace # (metastore_id, comment, timestamps), which is noise here and breaks the Cloud run. -trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time, value, owner})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json +trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time, owner, value})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json trace $CLI bundle deploy --var secret_value=secret-value trace print_requests.py //unity-catalog read_state.py secrets secret1 name expire_time title "Plan again to record any drift the removal leaves behind" trace $CLI bundle plan --var secret_value=secret-value -trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time, value, owner})}' > out.plan.drift.$DATABRICKS_BUNDLE_ENGINE.json +trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time, owner, value})}' > out.plan.drift.$DATABRICKS_BUNDLE_ENGINE.json rm -f "$OUT_REQUESTS" diff --git a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json index 2e72f38b765..2da131f5384 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json +++ b/acceptance/bundle/resources/secrets/update-expire-time/out.plan.direct.json @@ -7,17 +7,17 @@ "new": "[EXPIRE_TIME_AFTER]", "remote": "[EXPIRE_TIME_BEFORE]" }, + "owner": { + "action": "skip", + "reason": "spec:input_only", + "remote": "[USERNAME]" + }, "value": { "action": "skip", "reason": "custom", "old": "", "new": "[redacted]", "remote": "[redacted]" - }, - "owner": { - "action": "skip", - "reason": "spec:input_only", - "remote": "[USERNAME]" } } } diff --git a/acceptance/bundle/resources/secrets/update-expire-time/script b/acceptance/bundle/resources/secrets/update-expire-time/script index 7f32addde27..5114aaa644c 100644 --- a/acceptance/bundle/resources/secrets/update-expire-time/script +++ b/acceptance/bundle/resources/secrets/update-expire-time/script @@ -16,7 +16,7 @@ trace $CLI bundle plan --var secret_value=secret-value # Project to expire_time (the field this test is about): the full changes set now carries # output-only fields whose remote values differ between the testserver and a real workspace # (metastore_id, comment, timestamps), which is noise here and breaks the Cloud run. -trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time, value, owner})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json +trace $CLI bundle plan --var secret_value=secret-value -o json | nostamp | jq '.plan."resources.secrets.secret1" | {action, changes: (.changes | {expire_time, owner, value})}' > out.plan.$DATABRICKS_BUNDLE_ENGINE.json trace $CLI bundle deploy --var secret_value=secret-value trace print_requests.py //unity-catalog read_state.py secrets secret1 name expire_time