diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 8640ea0b51..743155e2c2 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -9,6 +9,7 @@ ### Bug Fixes * Expand the "workspace-level resource requires a workspace_id" error to list all sources checked (resource `provider_config`, provider `workspace_id`, the configured profile, and the `DATABRICKS_WORKSPACE_ID` environment variable) so users know where to set it ([#5763](https://github.com/databricks/terraform-provider-databricks/pull/5763)). +* Reject `workspace_id` values with a leading zero (e.g. `0470576644108500`) in `provider_config` so the literal value is no longer written to state where it would not match the canonical numeric workspace ID returned by the API ([#5764](https://github.com/databricks/terraform-provider-databricks/pull/5764)). ### Documentation diff --git a/common/unified_provider.go b/common/unified_provider.go index fd5aee337f..bd7ab5b30d 100644 --- a/common/unified_provider.go +++ b/common/unified_provider.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strconv" + "strings" "github.com/databricks/databricks-sdk-go" "github.com/databricks/databricks-sdk-go/client" @@ -30,8 +31,31 @@ type ProviderConfig struct { // workspaceIDValidateFunc is used to validate the workspace ID for the provider configuration. // Accepts either a classic numeric workspace ID or a connection ID that the platform gateway // can disambiguate via the X-Databricks-Workspace-Id header. +// +// All-digit values are treated as classic numeric workspace IDs and must be in +// canonical form: a leading zero (e.g. "0470576644108500") is rejected. Although +// strconv.ParseInt tolerates leading zeros and the resource would still be created +// in the correct workspace, the literal value is written verbatim to Terraform +// state, where it no longer matches the canonical numeric form returned by the API. +// That mismatch poisons every downstream string comparison (perpetual diffs, +// failed workspace_id reconciliation). Non-numeric connection IDs are left +// untouched so the platform gateway can disambiguate them server-side. func workspaceIDValidateFunc() func(interface{}, string) ([]string, []error) { - return validation.StringIsNotEmpty + return func(i interface{}, k string) ([]string, []error) { + if warnings, errs := validation.StringIsNotEmpty(i, k); len(errs) > 0 { + return warnings, errs + } + v := i.(string) + // Only constrain all-digit values; connection IDs (containing non-digit + // characters) are passed through unchanged. + if isNumericWorkspaceID(v) && len(v) > 1 && v[0] == '0' { + return nil, []error{fmt.Errorf( + "expected %s to be a numeric workspace ID without a leading zero, got %q; "+ + "use the canonical numeric form (e.g. %q)", + k, v, strings.TrimLeft(v, "0"))} + } + return nil, nil + } } // AddNamespaceInSchema adds the provider_config schema to the given schema map. diff --git a/common/unified_provider_test.go b/common/unified_provider_test.go index 4251597051..724c63fe8e 100644 --- a/common/unified_provider_test.go +++ b/common/unified_provider_test.go @@ -47,8 +47,18 @@ func TestWorkspaceIDValidateFunc(t *testing.T) { expectError: false, }, { - name: "value with leading zero now accepted", + name: "numeric value with leading zero rejected", input: "0123", + expectError: true, + }, + { + name: "numeric value with leading zero rejected - long form", + input: "0470576644108500", + expectError: true, + }, + { + name: "single zero accepted", + input: "0", expectError: false, }, { @@ -56,6 +66,11 @@ func TestWorkspaceIDValidateFunc(t *testing.T) { input: "abc123", expectError: false, }, + { + name: "connection ID with leading zero accepted", + input: "0abc-def-123", + expectError: false, + }, { name: "invalid empty string", input: "",