From ac31dc58b94476cbb0bb70e02c2e359df4c1e5d0 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Thu, 6 Aug 2026 03:10:01 +0200 Subject: [PATCH 1/6] chore: claim #123 From 6b9fa95031b731b7ae0a66b58192e08d25994e6d Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Thu, 6 Aug 2026 03:17:18 +0200 Subject: [PATCH 2/6] fix(repositories): declare org-enforced signoff so updates can apply Seven of the twenty Repository resources have been failing every update with 422 "Commit signoff is enforced by the organization and cannot be disabled", so declared repository configuration has not reached GitHub for them. The accepted explanation was that the field is rejected whenever it appears in an update, so #128 removed the declaration entirely. The live cluster shows the opposite. upjet builds the Terraform configuration from forProvider; an absent optional bool takes the provider's zero value of false; false against a live true is a permanent diff, so the payload carries web_commit_signoff_required: false and GitHub rejects it. The error names disabling, not presence. Declaring the live value leaves nothing to diff, so Terraform omits the field from the payload and the update applies. Measured, at two-minute resolution: 2026-07-27T04:33Z #125 merges, shared patch still declares the field 2026-07-27T04:34:5x nine write-enabled repos record LastAsyncOperation=Success 2026-07-27T14:42Z #128 removes the declaration 2026-07-27T14:44:4x the same repos begin recording AsyncUpdateFailure (422) Ten repositories still reconcile today only because the provider had already late-initialized the value into their spec, where Flux's removal could not reach it. The seven that never accumulated that residue are exactly the seven failing, and six of them differ from a working repository by this one field. So the write path currently depends on undeclared residue rather than on anything in this repository. platform-tenant-template is the one active resource holding no adopted values, so it cannot fall back on a previously observed visibility once updates apply again; its live value is pinned explicitly. tests/repository-update-policy.sh now pins the inverted invariant. Fixes #112 Co-Authored-By: Claude Opus 5 (1M context) --- AGENTS.md | 15 ++++-- .../archived-repositories/kustomization.yaml | 6 +-- deploy/repositories/agent-plugins.yaml | 4 +- deploy/repositories/agent-skills.yaml | 4 +- deploy/repositories/aws.yaml | 5 +- deploy/repositories/kustomization.yaml | 25 +++++---- deploy/repositories/kyverno-policies.yaml | 5 +- .../platform-tenant-template.yaml | 6 +++ deploy/repositories/provider-upjet-unifi.yaml | 5 +- tests/repository-update-policy.sh | 54 +++++++++++++------ 10 files changed, 83 insertions(+), 46 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3af73ad..a6e8bf3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,11 +43,16 @@ for the architecture, the GitHub App credential setup, and the Observe-first ado `crossplane.io/external-name` annotation to the live name and use a management policy that **excludes `Delete`** (observe/late-initialize), per platform's `docs/github-management.md`. Once adopted, an active `Repository` runs on `Observe`/`Create`/`Update` **without `LateInitialize`**: - late-initialized values land in `forProvider`, and everything in `forProvider` is sent on every - subsequent update PATCH. A field the org already enforces, such as `webCommitSignoffRequired`, is - declared in neither `forProvider` nor `initProvider`: GitHub rejects the whole PATCH with 422 - whenever that field appears in an update, even carrying its own current value, and upjet feeds both - of those blocks into the payload. The org setting applies it to new repositories anyway. Verify + late-initialized values land in `forProvider` and are then part of the resource's declared state. A + field the org already enforces, such as `webCommitSignoffRequired`, must be **declared in + `forProvider` at the value the org enforces** — never left unconfigured and never seeded through + the create-only `initProvider`. upjet builds the Terraform configuration from `forProvider`, an + absent optional bool takes the provider's zero value of `false`, and `false` against a live `true` + is a permanent diff, so every update PATCH carries `web_commit_signoff_required: false` and GitHub + rejects the whole request with 422 "Commit signoff is enforced ... and cannot be disabled". The + error names disabling, not presence: declaring the live value leaves nothing to diff, so Terraform + omits the field from the payload and the update applies. `tests/repository-update-policy.sh` pins + this. Verify the provider kind/field schema against the authoritative source ([crossplane-contrib/provider-upjet-github `package/crds/`](https://github.com/crossplane-contrib/provider-upjet-github) + `examples-generated/namespaced/`) — the CRs cannot be schema-validated locally (no cluster; CI diff --git a/deploy/archived-repositories/kustomization.yaml b/deploy/archived-repositories/kustomization.yaml index 39ff653..1a24093 100644 --- a/deploy/archived-repositories/kustomization.yaml +++ b/deploy/archived-repositories/kustomization.yaml @@ -1,7 +1,7 @@ # Archived (or archival-bound) repositories, kept OUTSIDE ../repositories/ on -# purpose: that kustomization's shared merge-policy patch (squash-only) targets -# every Repository it renders, and an archived repo is read-only for settings — -# each patched reconcile would 422 forever. +# purpose: that kustomization's shared merge-policy patch (squash-only + +# webCommitSignoffRequired) targets every Repository it renders, and an archived +# repo is read-only for settings — each patched reconcile would 422 forever. # CRs here get NO shared patches; they carry only what an archived repo can hold. # # Lifecycle (two-phase, per devantler-tech/actions#425 AC3): diff --git a/deploy/repositories/agent-plugins.yaml b/deploy/repositories/agent-plugins.yaml index 75a1e11..c462d6c 100644 --- a/deploy/repositories/agent-plugins.yaml +++ b/deploy/repositories/agent-plugins.yaml @@ -9,8 +9,8 @@ metadata: # external-name, so the provider observes directly and reconciles cleanly. crossplane.io/external-name: agent-plugins spec: - # The squash-only merge policy comes from the shared patch; commit signoff is - # declared nowhere and inherited from the organization. Description and topics + # The squash-only merge policy and the org-enforced commit signoff come from + # the shared patch. Description and topics # are declared here so the config is AUTHORITATIVE for them. Settings declared # nowhere here keep the value adopted from the live repo when it was first # observed. diff --git a/deploy/repositories/agent-skills.yaml b/deploy/repositories/agent-skills.yaml index 4aa16ed..110bf18 100644 --- a/deploy/repositories/agent-skills.yaml +++ b/deploy/repositories/agent-skills.yaml @@ -10,8 +10,8 @@ metadata: # reconciles cleanly. crossplane.io/external-name: agent-skills spec: - # The squash-only merge policy comes from the shared patch; commit signoff is - # declared nowhere and inherited from the organization. Description and topics + # The squash-only merge policy and the org-enforced commit signoff come from + # the shared patch. Description and topics # are declared here so the config is AUTHORITATIVE for them. Settings declared # nowhere here keep the value adopted from the live repo when it was first # observed. diff --git a/deploy/repositories/aws.yaml b/deploy/repositories/aws.yaml index e4aa2fc..6b9f3d1 100644 --- a/deploy/repositories/aws.yaml +++ b/deploy/repositories/aws.yaml @@ -23,9 +23,8 @@ spec: description: "Declarative AWS infrastructure for the devantler-tech platform — Crossplane managed resources in deploy/, published as a cosign-signed OCI artifact and reconciled by the platform's aws tenant." visibility: public hasIssues: true - # Shared kustomization patch supplies the squash-only merge policy; commit - # signoff is inherited from the organization and declared nowhere. Nothing - # repo-specific needed here. + # Shared kustomization patch supplies the squash-only merge policy and the + # org-enforced commit signoff; nothing repo-specific needed here. providerConfigRef: kind: ProviderConfig name: default diff --git a/deploy/repositories/kustomization.yaml b/deploy/repositories/kustomization.yaml index a0b44de..4eab00c 100644 --- a/deploy/repositories/kustomization.yaml +++ b/deploy/repositories/kustomization.yaml @@ -36,15 +36,19 @@ resources: # (auto-applies to every future repo): # - squash-only merge policy (merge commits + rebase disabled; auto-merge, # auto-delete head branches, always-suggest-updating-PR-branches enabled). -# - webCommitSignoffRequired is declared NOWHERE, on purpose. The org enforces -# commit signoff, and GitHub rejects the whole PATCH with 422 "Commit signoff -# is enforced ... and cannot be disabled" whenever the field appears in a -# repository update — including when it carries its own current value of true. -# The Terraform provider omits the field from the payload only while it is -# left unconfigured, and upjet builds that configuration from forProvider and -# initProvider alike, so declaring it in either one reinstates the 422. -# Omitting it costs nothing: the org setting is what applies signoff to a new -# repository, and it is the same setting that makes the field unwritable. +# - webCommitSignoffRequired: true — declared precisely BECAUSE the org enforces +# it. Leaving the field unconfigured is what breaks updates, not declaring it. +# upjet builds the Terraform configuration from forProvider, an absent optional +# bool takes the provider's zero value of false, and false against a live true +# is a permanent diff — so every update PATCH carries +# web_commit_signoff_required: false and GitHub rejects the whole request with +# 422 "Commit signoff is enforced ... and cannot be disabled". The error names +# disabling, not presence. Declaring the live value leaves nothing to diff, so +# Terraform omits the field from the payload and the rest of the update +# applies. Measured: with this line present, nine write-enabled repositories +# completed update PATCHes at 2026-07-27T04:34:5xZ; two minutes after it was +# removed the same repositories began failing on that 422, and seven were +# still failing on 2026-08-06. See #112. # - hasDownloads: false — GitHub has removed the downloads feature and no # longer returns the field, so status.atProvider never carries it. The # Terraform provider still defaults it to true, so a spec holding that default @@ -78,6 +82,9 @@ patches: - op: add path: /spec/forProvider/deleteBranchOnMerge value: true + - op: add + path: /spec/forProvider/webCommitSignoffRequired + value: true - op: add path: /spec/forProvider/hasDownloads value: false diff --git a/deploy/repositories/kyverno-policies.yaml b/deploy/repositories/kyverno-policies.yaml index 21bcf03..7f0a7d2 100644 --- a/deploy/repositories/kyverno-policies.yaml +++ b/deploy/repositories/kyverno-policies.yaml @@ -24,9 +24,8 @@ spec: description: "Shared Kyverno policy library for the devantler-tech platforms — the single source the platform and platform-template consume instead of vendoring per-repo copies." visibility: public hasIssues: true - # Shared kustomization patch supplies the squash-only merge policy; commit - # signoff is inherited from the organization and declared nowhere. Nothing - # repo-specific needed here. + # Shared kustomization patch supplies the squash-only merge policy and the + # org-enforced commit signoff; nothing repo-specific needed here. providerConfigRef: kind: ProviderConfig name: default diff --git a/deploy/repositories/platform-tenant-template.yaml b/deploy/repositories/platform-tenant-template.yaml index 2aa1c66..12eb7dc 100644 --- a/deploy/repositories/platform-tenant-template.yaml +++ b/deploy/repositories/platform-tenant-template.yaml @@ -17,6 +17,12 @@ spec: - Update forProvider: name: platform-tenant-template + # Pinned because this resource carries no adopted values: it is the one + # active repository whose spec holds nothing beyond what the config declares, + # so an update cannot fall back on a previously observed visibility the way + # every other repository here can. Declaring the live value keeps restoring + # the write path (#112) from being able to change it. + visibility: public description: "Template for platform tenants on the devantler-tech platform — framework-agnostic CI/CD plumbing kept current via template-sync." providerConfigRef: kind: ProviderConfig diff --git a/deploy/repositories/provider-upjet-unifi.yaml b/deploy/repositories/provider-upjet-unifi.yaml index 470d4d9..9df6584 100644 --- a/deploy/repositories/provider-upjet-unifi.yaml +++ b/deploy/repositories/provider-upjet-unifi.yaml @@ -19,9 +19,8 @@ spec: description: "Crossplane provider for Ubiquiti UniFi, generated with Upjet from ubiquiti-community/terraform-provider-unifi. Manage UniFi networks, WLANs, firewall, VPN/WireGuard, devices and settings as Kubernetes resources." visibility: public hasIssues: true - # Shared kustomization patch supplies the squash-only merge policy; commit - # signoff is inherited from the organization and declared nowhere. Nothing - # repo-specific needed here. + # Shared kustomization patch supplies the squash-only merge policy and the + # org-enforced commit signoff; nothing repo-specific needed here. providerConfigRef: kind: ProviderConfig name: default diff --git a/tests/repository-update-policy.sh b/tests/repository-update-policy.sh index 3a13d3d..77d227c 100755 --- a/tests/repository-update-policy.sh +++ b/tests/repository-update-policy.sh @@ -58,28 +58,50 @@ unsafe_policies="$( [[ -z "$unsafe_policies" ]] || fail "active Repository resources must not pair Update with LateInitialize, must exclude Delete, and must Observe: $unsafe_policies" -# The org enforces commit signoff, and GitHub rejects the entire PATCH with 422 -# whenever this field appears in a repository update — measured against the live -# API, sending the field at its own current value of true still fails. The -# Terraform provider only omits it from the payload when it is left unconfigured, -# and upjet feeds BOTH forProvider and initProvider into that configuration, so -# either one puts the field back into every update. It must appear in neither. -# Nothing is lost by omitting it: the org setting is what applies signoff to a -# new repository, which is the same policy that makes the field unwritable here. -declared_signoff="$( +# Every active repository must declare webCommitSignoffRequired: true in +# forProvider, because the org enforces commit signoff and live is therefore +# always true. Leaving the field unconfigured does NOT keep it out of the update +# payload: upjet builds the Terraform configuration from forProvider, an absent +# optional bool takes the provider's zero value of false, and false against a +# live true is a permanent diff — so every update PATCH carries +# web_commit_signoff_required: false and GitHub rejects the whole request with +# 422 "Commit signoff is enforced by the organization and cannot be disabled". +# Declaring the live value leaves nothing to diff, so Terraform omits the field +# from the payload and the rest of the update applies. +# +# The 422 names disabling, not presence, and the cluster agrees: at +# 2026-07-27T04:34:5xZ, with this field declared by the shared patch, nine +# write-enabled repositories recorded LastAsyncOperation=Success — completed +# update PATCHes. Two minutes after the declaration was removed the same +# repositories began recording AsyncUpdateFailure carrying that 422, and seven +# were still failing on 2026-08-06. See devantler-tech/.github#123. +# +# initProvider is not a substitute: Crossplane applies it only at creation, so +# forProvider stays unconfigured and the permanent diff above is unchanged. +missing_signoff="$( yq -N ' select( .kind == "Repository" and .spec.forProvider.archived != true and - ( - (.spec.forProvider | has("webCommitSignoffRequired")) or - (.spec.initProvider | has("webCommitSignoffRequired")) - ) + .spec.forProvider.webCommitSignoffRequired != true + ) | + .metadata.name + ' "$render" +)" +[[ -z "$missing_signoff" ]] || + fail "active Repository resources must declare forProvider.webCommitSignoffRequired: true so updates carry no disabling value: $missing_signoff" + +seeded_signoff="$( + yq -N ' + select( + .kind == "Repository" and + .spec.forProvider.archived != true and + (.spec.initProvider | has("webCommitSignoffRequired")) ) | .metadata.name ' "$render" )" -[[ -z "$declared_signoff" ]] || - fail "org-controlled signoff must not be declared in forProvider or initProvider: $declared_signoff" +[[ -z "$seeded_signoff" ]] || + fail "signoff must be declared in forProvider, not the create-only initProvider: $seeded_signoff" -echo "repository-update-policy: OK — $active_count active repositories leave signoff to the org" +echo "repository-update-policy: OK — $active_count active repositories declare org-enforced signoff" From d4d0e85611b2accd2c7a79e407c670638a78b276 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Thu, 6 Aug 2026 03:18:15 +0200 Subject: [PATCH 3/6] docs(repositories): point signoff rationale at the tracking issue --- deploy/repositories/platform-tenant-template.yaml | 4 ++-- tests/repository-update-policy.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/repositories/platform-tenant-template.yaml b/deploy/repositories/platform-tenant-template.yaml index 12eb7dc..bcc0b85 100644 --- a/deploy/repositories/platform-tenant-template.yaml +++ b/deploy/repositories/platform-tenant-template.yaml @@ -20,8 +20,8 @@ spec: # Pinned because this resource carries no adopted values: it is the one # active repository whose spec holds nothing beyond what the config declares, # so an update cannot fall back on a previously observed visibility the way - # every other repository here can. Declaring the live value keeps restoring - # the write path (#112) from being able to change it. + # every other repository here can. Declaring the live value is what makes + # restoring the write path (#112) unable to change it. visibility: public description: "Template for platform tenants on the devantler-tech platform — framework-agnostic CI/CD plumbing kept current via template-sync." providerConfigRef: diff --git a/tests/repository-update-policy.sh b/tests/repository-update-policy.sh index 77d227c..34223e2 100755 --- a/tests/repository-update-policy.sh +++ b/tests/repository-update-policy.sh @@ -74,7 +74,7 @@ unsafe_policies="$( # write-enabled repositories recorded LastAsyncOperation=Success — completed # update PATCHes. Two minutes after the declaration was removed the same # repositories began recording AsyncUpdateFailure carrying that 422, and seven -# were still failing on 2026-08-06. See devantler-tech/.github#123. +# were still failing on 2026-08-06. See devantler-tech/.github#112. # # initProvider is not a substitute: Crossplane applies it only at creation, so # forProvider stays unconfigured and the permanent diff above is unchanged. From 058c81997ac82fc191afc2540cccb65ed225e518 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Thu, 6 Aug 2026 03:28:30 +0200 Subject: [PATCH 4/6] docs(agents): bound LateInitialize residue to the adoption phase CodeRabbit: the previous wording let 'late-initialized values land in forProvider' read as an ongoing behaviour. Once LateInitialize is removed no newly observed field is copied in again, which is precisely why a resource adopted without a field can never acquire it and the config must supply it. --- AGENTS.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index a6e8bf3..6ed40d4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,7 +43,9 @@ for the architecture, the GitHub App credential setup, and the Observe-first ado `crossplane.io/external-name` annotation to the live name and use a management policy that **excludes `Delete`** (observe/late-initialize), per platform's `docs/github-management.md`. Once adopted, an active `Repository` runs on `Observe`/`Create`/`Update` **without `LateInitialize`**: - late-initialized values land in `forProvider` and are then part of the resource's declared state. A + the values late-initialized *during adoption* stay in `forProvider` as provider-owned state, and + once `LateInitialize` is gone **no newly observed field is ever copied in again** — so a resource + adopted without a given field never acquires it, and nothing but the config can supply it. A field the org already enforces, such as `webCommitSignoffRequired`, must be **declared in `forProvider` at the value the org enforces** — never left unconfigured and never seeded through the create-only `initProvider`. upjet builds the Terraform configuration from `forProvider`, an From 25b48f0db742c6406b8138aeba7066419fedb114 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Thu, 6 Aug 2026 18:10:07 +0200 Subject: [PATCH 5/6] fix(repositories): correct stale private declarations before restoring writes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ascoachingogvaner and wedding-app are public and serve live sites, but both declared visibility: private — carried in from the template they were written against, never true of either repository. While updates were write-blocked the divergence was inert; restoring the write path is what would make it act, so the declaration is corrected first and the two stay Observe-only until promoted separately. The kustomization grouped them under '# Private repos.', which described neither their visibility nor their management policy. fleet-gitops, which is genuinely private and fully managed, moves in with the actively-managed set. Part of #123 --- deploy/repositories/ascoachingogvaner.yaml | 16 ++++++++-------- deploy/repositories/kustomization.yaml | 8 ++++++-- deploy/repositories/wedding-app.yaml | 16 ++++++++-------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/deploy/repositories/ascoachingogvaner.yaml b/deploy/repositories/ascoachingogvaner.yaml index 4858c9a..c27c0d7 100644 --- a/deploy/repositories/ascoachingogvaner.yaml +++ b/deploy/repositories/ascoachingogvaner.yaml @@ -5,18 +5,18 @@ metadata: annotations: crossplane.io/external-name: ascoachingogvaner spec: - # Observe-only: this file declares `visibility: private` while the live - # repository is public and serving a site, so acting on the declaration would - # take the site off the public internet. Which side is wrong is the - # maintainer's call, tracked on devantler-tech/.github#123 — until it is made, - # Crossplane mirrors this repo read-only and writes nothing. Restoring - # Create/Update is what enacts the decision, once `visibility` below has been - # set to the answer. + # Observe-only while the declared value catches up with reality. The repository + # is public and serves the live AS Coaching og Vaner site, so `public` below is + # the live value, not a change of policy — the previous `private` was carried in + # from the template this file was written against and was never true of this + # repository. Restoring Create/Update is a separate step, tracked on + # devantler-tech/.github#123; it is safe to take only because declared and live + # now agree, so enabling writes can no longer take the site off the internet. managementPolicies: - Observe forProvider: name: ascoachingogvaner - visibility: private + visibility: public archived: false description: "AS Coaching og Vaner — coaching website (platform tenant)" providerConfigRef: diff --git a/deploy/repositories/kustomization.yaml b/deploy/repositories/kustomization.yaml index 4eab00c..73f8765 100644 --- a/deploy/repositories/kustomization.yaml +++ b/deploy/repositories/kustomization.yaml @@ -28,10 +28,14 @@ resources: - homebrew-tap.yaml - world-at-ruin.yaml - doggy-countdown.yaml - # Private repos. + - fleet-gitops.yaml + # Observe-only (read-only mirror; Crossplane writes nothing). These two are + # public and serve live sites. They are listed apart because of their + # management policy, not their visibility — grouping them as "private repos" + # described neither correctly. Promoting them to Observe/Create/Update is + # tracked on devantler-tech/.github#123. - ascoachingogvaner.yaml - wedding-app.yaml - - fleet-gitops.yaml # Org-wide repo settings applied to EVERY Repository, single source of truth # (auto-applies to every future repo): # - squash-only merge policy (merge commits + rebase disabled; auto-merge, diff --git a/deploy/repositories/wedding-app.yaml b/deploy/repositories/wedding-app.yaml index 07c2d2d..e80ff1b 100644 --- a/deploy/repositories/wedding-app.yaml +++ b/deploy/repositories/wedding-app.yaml @@ -5,18 +5,18 @@ metadata: annotations: crossplane.io/external-name: wedding-app spec: - # Observe-only: this file declares `visibility: private` while the live - # repository is public and serving a site, so acting on the declaration would - # take the site off the public internet. Which side is wrong is the - # maintainer's call, tracked on devantler-tech/.github#123 — until it is made, - # Crossplane mirrors this repo read-only and writes nothing. Restoring - # Create/Update is what enacts the decision, once `visibility` below has been - # set to the answer. + # Observe-only while the declared value catches up with reality. The repository + # is public and serves the live wedding site, so `public` below is the live + # value, not a change of policy — the previous `private` was carried in from the + # template this file was written against and was never true of this repository. + # Restoring Create/Update is a separate step, tracked on + # devantler-tech/.github#123; it is safe to take only because declared and live + # now agree, so enabling writes can no longer take the site off the internet. managementPolicies: - Observe forProvider: name: wedding-app - visibility: private + visibility: public archived: false description: "A simple wedding API service deployed to the devantler-tech/platform Kubernetes cluster." providerConfigRef: From 7c2e2b382719f6467506f663cdd9594d4823d1d1 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Thu, 6 Aug 2026 22:17:56 +0200 Subject: [PATCH 6/6] docs(repositories): state the current management rationale, not the migration The two observe-only declarations described the change this PR makes rather than the state it leaves behind. Both now say why write management is still disabled and where enabling it is tracked. --- deploy/repositories/ascoachingogvaner.yaml | 12 +++++------- deploy/repositories/wedding-app.yaml | 12 +++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/deploy/repositories/ascoachingogvaner.yaml b/deploy/repositories/ascoachingogvaner.yaml index c27c0d7..61229d4 100644 --- a/deploy/repositories/ascoachingogvaner.yaml +++ b/deploy/repositories/ascoachingogvaner.yaml @@ -5,13 +5,11 @@ metadata: annotations: crossplane.io/external-name: ascoachingogvaner spec: - # Observe-only while the declared value catches up with reality. The repository - # is public and serves the live AS Coaching og Vaner site, so `public` below is - # the live value, not a change of policy — the previous `private` was carried in - # from the template this file was written against and was never true of this - # repository. Restoring Create/Update is a separate step, tracked on - # devantler-tech/.github#123; it is safe to take only because declared and live - # now agree, so enabling writes can no longer take the site off the internet. + # Observe-only: Crossplane mirrors this repository read-only and writes nothing. + # The repository is public and serves the live AS Coaching og Vaner site, and the + # visibility below states that live value — so enacting this declaration would be + # a no-op rather than a change. Enabling Create/Update is a separate, deliberate + # step, tracked on devantler-tech/.github#123. managementPolicies: - Observe forProvider: diff --git a/deploy/repositories/wedding-app.yaml b/deploy/repositories/wedding-app.yaml index e80ff1b..2ec88eb 100644 --- a/deploy/repositories/wedding-app.yaml +++ b/deploy/repositories/wedding-app.yaml @@ -5,13 +5,11 @@ metadata: annotations: crossplane.io/external-name: wedding-app spec: - # Observe-only while the declared value catches up with reality. The repository - # is public and serves the live wedding site, so `public` below is the live - # value, not a change of policy — the previous `private` was carried in from the - # template this file was written against and was never true of this repository. - # Restoring Create/Update is a separate step, tracked on - # devantler-tech/.github#123; it is safe to take only because declared and live - # now agree, so enabling writes can no longer take the site off the internet. + # Observe-only: Crossplane mirrors this repository read-only and writes nothing. + # The repository is public and serves the live wedding site, and the visibility + # below states that live value — so enacting this declaration would be a no-op + # rather than a change. Enabling Create/Update is a separate, deliberate step, + # tracked on devantler-tech/.github#123. managementPolicies: - Observe forProvider: