From c4c8d4635ecdddd33b1dc4f014274358bf10c66b Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sat, 27 Jun 2026 10:35:14 +0200 Subject: [PATCH] fix(rulesets): use bare numeric external-name for repository rulesets The two RepositoryRuleset resources set crossplane.io/external-name to the Terraform *import* id format `:` (`ksail:14699634`, `platform:5275020`) instead of the bare numeric ruleset id the upjet provider stores (RepositoryRuleset is config.IdentifierFromProvider, exactly like the working OrganizationRuleset siblings, which all use bare numeric ids and sync fine). The provider strconv.ParseInt's the external-name and fails: observe failed: ... Unexpected ID format ("ksail:14699634"), expected numerical ID. strconv.ParseInt: parsing "ksail:14699634": invalid syntax so both resources are stuck SYNCED=False and Coroot raises recurring `CannotObserveExternalResource` events on prod. Strip the `:` prefix (the numeric part is already the correct ruleset id, verified against the live GitHub API) and fix the misleading convention note here and in the README. These are managementPolicies: ["Observe"] (read-only) so there is zero blast radius on the real GitHub rulesets. Co-Authored-By: Claude Opus 4.8 --- deploy/repository-rulesets/README.md | 6 +++++- .../require-merge-queue-on-platform.yaml | 9 ++++++--- .../repository-rulesets/restrict-deletions-on-ksail.yaml | 9 ++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/deploy/repository-rulesets/README.md b/deploy/repository-rulesets/README.md index a005e1b..2e7fb5b 100644 --- a/deploy/repository-rulesets/README.md +++ b/deploy/repository-rulesets/README.md @@ -9,7 +9,11 @@ Org-wide `OrganizationRuleset` resources live in the sibling adoption convention and the provider importability matrix. **One `RepositoryRuleset` per file**, named `-on-.yaml` so the rule and its -target repo are clear from the filename. external-name = `:`. +target repo are clear from the filename. external-name = the **bare numeric ruleset id** +(same as `../organization-rulesets/`; the provider stores `RepositoryRuleset.id` +from-provider). The Terraform `:` form is the *import* id only — using +it as the external-name fails the provider's `strconv.ParseInt` so the resource never +observes. | File | Repo | Ruleset | Policy | |---|---|---|---| diff --git a/deploy/repository-rulesets/require-merge-queue-on-platform.yaml b/deploy/repository-rulesets/require-merge-queue-on-platform.yaml index 3d3a296..879555f 100644 --- a/deploy/repository-rulesets/require-merge-queue-on-platform.yaml +++ b/deploy/repository-rulesets/require-merge-queue-on-platform.yaml @@ -1,6 +1,9 @@ # Existing repository ruleset, adopted Observe-first (read-only). external-name = -# `:` (cf. the `maintainers:` convention in -# ../teams/). Identity-only forProvider — see ./README.md for the convention. +# the bare numeric ruleset id — the upjet provider stores RepositoryRuleset `id` +# from-provider, exactly like ../organization-rulesets/. (The Terraform +# `:` form is the *import* id, NOT the stored external-name; a +# `:`-prefixed value fails the provider's strconv.ParseInt and the resource +# never observes.) Identity-only forProvider — see ./README.md for the convention. # # platform's "Require merge queue" rule on the default branch (merge_queue is a # repo-only rule type; org rulesets cannot carry it). @@ -9,7 +12,7 @@ kind: RepositoryRuleset metadata: name: platform-require-merge-queue annotations: - crossplane.io/external-name: "platform:5275020" + crossplane.io/external-name: "5275020" # numeric ruleset id spec: managementPolicies: ["Observe"] forProvider: diff --git a/deploy/repository-rulesets/restrict-deletions-on-ksail.yaml b/deploy/repository-rulesets/restrict-deletions-on-ksail.yaml index 68555df..fc51535 100644 --- a/deploy/repository-rulesets/restrict-deletions-on-ksail.yaml +++ b/deploy/repository-rulesets/restrict-deletions-on-ksail.yaml @@ -1,6 +1,9 @@ # Existing repository ruleset, adopted Observe-first (read-only). external-name = -# `:` (cf. the `maintainers:` convention in -# ../teams/). Identity-only forProvider — see ./README.md for the convention. +# the bare numeric ruleset id — the upjet provider stores RepositoryRuleset `id` +# from-provider, exactly like ../organization-rulesets/. (The Terraform +# `:` form is the *import* id, NOT the stored external-name; a +# `:`-prefixed value fails the provider's strconv.ParseInt and the resource +# never observes.) Identity-only forProvider — see ./README.md for the convention. # # ksail's own "Restrict deletions" rule, scoped to refs/heads/benchmark-data (the # long-lived benchmark-data branch) — narrower than the org-wide rule. @@ -9,7 +12,7 @@ kind: RepositoryRuleset metadata: name: ksail-restrict-deletions annotations: - crossplane.io/external-name: "ksail:14699634" + crossplane.io/external-name: "14699634" # numeric ruleset id spec: managementPolicies: ["Observe"] forProvider: