From d8392192bd53cb6678b3aa3bed347f46d7ce630d Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Fri, 10 Jul 2026 22:32:43 +0200 Subject: [PATCH 1/3] docs: add CLAUDE.md shim + deploy/ credential-refresh and authoring guidance --- CLAUDE.md | 1 + deploy/README.md | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/deploy/README.md b/deploy/README.md index 056922e..a64143a 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -45,6 +45,37 @@ out-of-band changes made in the GitHub UI. and activation of `repositorypermissions.actions.github.m.upbound.io` in the platform MRAP. +## Credentials & refresh behavior + +The provider authenticates as a GitHub App whose credentials are **not** stored +here: [`external-secret.yaml`](external-secret.yaml) is an +[External Secrets](https://external-secrets.io) `ExternalSecret` that syncs them +from the platform cluster's OpenBao `SecretStore` into the `github-app-credentials` +Secret consumed by [`provider-config.yaml`](provider-config.yaml), re-reading the +source every `refreshInterval: 1h`. Two operational consequences: + +- **A credential rotated in OpenBao propagates within the hour** — no manifest + change or redeploy needed. +- **OpenBao being unreachable does not break reconciliation immediately**: the + ExternalSecret reports `SecretSynced=False` but the last-synced Secret stays in + place, so Crossplane keeps reconciling on cached credentials until a refresh + succeeds (or the credentials themselves expire). A `SecretSynced=False` alone is + therefore a degraded-refresh signal, not an outage of the github-config tenant. + +## Authoring changes + +The authoring conventions live in the repo's [`AGENTS.md`](../AGENTS.md) (the +canonical instructions file, for humans and AI agents alike) — in short: +declarative-only (never `gh api` writes or UI changes to managed config), +**Observe-first** adoption of live objects (`crossplane.io/external-name` + +a management policy excluding `Delete`), team-based ownership, and +`IssueLabels` declared as a complete superset of a repo's live labels. Validate +before every PR with exactly what CI runs: + +```sh +kubectl kustomize deploy/ > /dev/null +``` + See the platform repo's [`docs/github-management.md`](https://github.com/devantler-tech/platform/blob/main/docs/github-management.md) for the architecture, the GitHub App credential setup, and the **Observe-first** From 3ec9226a775ed871740d45da217659e99bdc4189 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Fri, 10 Jul 2026 23:27:42 +0200 Subject: [PATCH 2/3] docs: complete agent shims and deploy roadmap --- GEMINI.md | 1 + deploy/README.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 GEMINI.md diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/GEMINI.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/deploy/README.md b/deploy/README.md index a64143a..446a9f1 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -45,6 +45,21 @@ out-of-band changes made in the GitHub UI. and activation of `repositorypermissions.actions.github.m.upbound.io` in the platform MRAP. +## Roadmap + +GitHub Issues are the roadmap of record. Epic +[#56](https://github.com/devantler-tech/.github/issues/56) tracks the current +GitHub-as-code programme in three phases: + +1. **Foundation** — publish the signed artifact and Observe-adopt repositories, + teams, and provider credentials without assuming delete ownership (landed). +2. **Coverage** — extend the declarative source of truth across labels, + rulesets, team access, repository metadata, and remaining org settings + through the epic's linked children (active). +3. **Enforcement** — move each supported object from observation to active + reconciliation only after its live state matches the manifest; retain the + no-`Delete` policy until deletion is explicitly designed and reviewed. + ## Credentials & refresh behavior The provider authenticates as a GitHub App whose credentials are **not** stored From 47bcfa6ee0348933a3ba907355b3bf682a9ba110 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sat, 11 Jul 2026 18:27:07 +0200 Subject: [PATCH 3/3] docs(deploy): watch the ExternalSecret Ready condition, not the SecretSynced reason --- deploy/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index 446a9f1..4264bad 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -72,9 +72,10 @@ source every `refreshInterval: 1h`. Two operational consequences: - **A credential rotated in OpenBao propagates within the hour** — no manifest change or redeploy needed. - **OpenBao being unreachable does not break reconciliation immediately**: the - ExternalSecret reports `SecretSynced=False` but the last-synced Secret stays in - place, so Crossplane keeps reconciling on cached credentials until a refresh - succeeds (or the credentials themselves expire). A `SecretSynced=False` alone is + ExternalSecret's `Ready` condition goes `False` (typically with reason + `SecretSyncedError`) but the last-synced Secret stays in place, so Crossplane + keeps reconciling on cached credentials until a refresh succeeds (or the + credentials themselves expire). A `Ready=False` refresh error alone is therefore a degraded-refresh signal, not an outage of the github-config tenant. ## Authoring changes