RPF-WP-0044-T06: ESO adoption prep, readiness receipts and founder runbook
Source gate passes; predecessor proofs stale/missing smoke; live diff and store baseline blocked on agent cluster read access after CUST-WP-0073. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 527080@bnt-lap001 Assistant-Session: 5a0e864a-67be-4605-a77a-16635f7dd292
This commit is contained in:
parent
8761da9027
commit
fd2f808cd8
4 changed files with 164 additions and 1 deletions
67
docs/evidence/2026-10-21-eso-adoption-prep/prep-receipt.json
Normal file
67
docs/evidence/2026-10-21-eso-adoption-prep/prep-receipt.json
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"schema": "railiance-platform.eso-adoption-prep/v1",
|
||||
"task": "RPF-WP-0044-T06",
|
||||
"captured_at": "2026-10-21",
|
||||
"approval_ref": "89f1058f-33bc-47a8-8a49-0b44d426c67e",
|
||||
"readiness_gate": {
|
||||
"receipt": "readiness-r1.json",
|
||||
"source_ready": true,
|
||||
"missing_or_invalid": [
|
||||
"RPF-WP-0044-T04",
|
||||
"RPF-WP-0044-T05"
|
||||
],
|
||||
"T04_reason": "docs/evidence/2026-10-20-issue-core-verify-live.json lacks authenticated_ingest_status=201 and authenticated_close_status=200 (verify-live ran without --smoke) and is older than the 300 s freshness window",
|
||||
"T05_reason": "gate requires a fresh (<=300 s) argocd-workload-adoption-proof/v1 receipt; the 2026-10-11 receipt is stale. A fresh read-only run (scripts/workload_adoption_proof.py --live) failed because ssh railiance01 (user tegwick) can no longer read /etc/rancher/k3s/k3s.yaml after the CUST-WP-0073 cutover",
|
||||
"smoke_not_run": "verify-live --smoke creates and closes a Forgejo issue; not read-only, so not run under the preparation-only boundary"
|
||||
},
|
||||
"offline_render": {
|
||||
"chart": "external-secrets 0.16.1",
|
||||
"values_source": "argocd/railiance01/drafts/external-secrets.application.yaml",
|
||||
"render_sha256": "55236645afc9f2d9d376c28e73aed70bd31727d0e6f166664b3ebd568d5f136f",
|
||||
"objects": 39,
|
||||
"kinds": {
|
||||
"ServiceAccount": 3,
|
||||
"Secret": 1,
|
||||
"CustomResourceDefinition": 20,
|
||||
"ClusterRole": 5,
|
||||
"ClusterRoleBinding": 2,
|
||||
"Role": 1,
|
||||
"RoleBinding": 1,
|
||||
"Service": 1,
|
||||
"Deployment": 3,
|
||||
"ValidatingWebhookConfiguration": 2
|
||||
},
|
||||
"crds": 20,
|
||||
"crds_prune_delete_protected": 20,
|
||||
"store_or_externalsecret_objects_rendered": [],
|
||||
"kinds_with_cabundle": [
|
||||
"CustomResourceDefinition/clustergenerators.generators.external-secrets.io",
|
||||
"CustomResourceDefinition/clustersecretstores.external-secrets.io",
|
||||
"CustomResourceDefinition/secretstores.external-secrets.io",
|
||||
"CustomResourceDefinition/vaultdynamicsecrets.generators.external-secrets.io",
|
||||
"CustomResourceDefinition/webhooks.generators.external-secrets.io"
|
||||
],
|
||||
"credential_kind_objects_rendered": [
|
||||
"external-secrets-webhook"
|
||||
],
|
||||
"notes": [
|
||||
"20/20 CRDs carry argocd.argoproj.io/sync-options Prune=false,Delete=false",
|
||||
"no ClusterSecretStore/SecretStore/ExternalSecret objects rendered, so adoption cannot delete or replace any store or ExternalSecret",
|
||||
"the one rendered credential-kind object is the empty webhook certificate holder (metadata only, no data key); server-side apply does not take ownership of the cert-controller-injected data",
|
||||
"ValidatingWebhookConfigurations declare no caBundle and no CRD declares a conversion webhook (caBundle hits are schema text); no ignoreDifferences added because no diff has shown drift yet"
|
||||
]
|
||||
},
|
||||
"draft_policy": {
|
||||
"automated": false,
|
||||
"finalizers": false,
|
||||
"ServerSideApply": true,
|
||||
"Force_or_Replace": false,
|
||||
"prune_in_sync_command": false
|
||||
},
|
||||
"not_done_live": {
|
||||
"fresh_native_client_side_diff": "blocked: no agent kube read path on railiance01 (tegwick kubeconfig removed; custodian-agent observer role has no CRD/RBAC/webhook/ESO read)",
|
||||
"store_baseline": "blocked: same reason; expected ValidationFailed: openbao-activity-core, openbao-email-connect"
|
||||
},
|
||||
"native_mutation": false,
|
||||
"secret_values_observed_by_agent": false
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"approval_ref": "89f1058f-33bc-47a8-8a49-0b44d426c67e", "checks": {"source": {"chart_pin": "0.16.1", "crd_prune_delete_protected": true, "manual_sync_only": true, "server_side_apply": true}}, "founder_approval_required": false, "live_or_credential_calls": false, "missing_or_invalid": ["RPF-WP-0044-T04", "RPF-WP-0044-T05"], "native_mutation": false, "next_action": "wait_for_predecessor_automated_proof", "ready_for_fresh_native_render_diff": false, "schema": "eso-adoption-readiness/v1", "source_ready": true, "task": "RPF-WP-0044-T06"}
|
||||
93
docs/runbooks/rpf-wp-0044-t06-eso-adoption.md
Normal file
93
docs/runbooks/rpf-wp-0044-t06-eso-adoption.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# RPF-WP-0044-T06 — adopt external-secrets into Argo (founder runbook)
|
||||
|
||||
Authority: D2 (`89f1058f-33bc-47a8-8a49-0b44d426c67e`). No further founder approval is needed.
|
||||
Highest-risk adoption: ESO serves every ExternalSecret on railiance01. Prep receipt:
|
||||
`docs/evidence/2026-10-21-eso-adoption-prep/prep-receipt.json`.
|
||||
|
||||
## State at preparation (2026-10-21, agent, offline only)
|
||||
|
||||
- Draft `argocd/railiance01/drafts/external-secrets.application.yaml`: chart `0.16.1`,
|
||||
`ServerSideApply=true`, no `automated`, no finalizer, no Force/Replace, and CRD values
|
||||
`crds.annotations: argocd.argoproj.io/sync-options: Prune=false,Delete=false`. The readiness gate
|
||||
passes the source check.
|
||||
- Offline render (render sha256 `55236645…f136f`): 39 objects, made up of 20 CRDs (all 20
|
||||
prune/delete protected), 3 Deployments, 3 ServiceAccounts, 5 ClusterRoles, 2 ClusterRoleBindings,
|
||||
1 Role, 1 RoleBinding, 1 Service, 2 ValidatingWebhookConfigurations and the empty webhook-cert
|
||||
holder (metadata only). **No ClusterSecretStore or ExternalSecret is rendered**, so adoption cannot
|
||||
delete or replace a store. The webhooks declare no `caBundle`, so server-side apply does not take
|
||||
it from the cert-controller. `ignoreDifferences` is added only if the diff below shows drift.
|
||||
- **Not done by the agent:** the fresh live diff, the store baseline and the fresh predecessor proofs.
|
||||
Since the CUST-WP-0073 cutover (2026-10-20) the agent's `ssh railiance01` login (`tegwick`) cannot
|
||||
read the k3s kubeconfig, and the custodian-agent observer role has no CRD, RBAC, webhook or ESO read.
|
||||
Run every `ssh railiance01 "kubectl …"` below through a login that still has cluster-admin read.
|
||||
|
||||
## 1. Pre-check (founder, or agent once read access exists)
|
||||
|
||||
```bash
|
||||
cd ~/railiance-platform && git pull --ff-only
|
||||
D=docs/evidence/2026-10-21-eso-adoption-prep
|
||||
# a) fresh predecessor proofs (gate window is 300 s, so run all three back to back)
|
||||
( cd ~/rapp-issue-core && make -s verify-live VERIFY_ARGS="--expected-revision 186c817b67d3919a64acdddbd3889e539841f946 --expected-source-url ssh://git@forgejo.coulomb.social:30022/coulomb/rapp-issue-core.git --smoke" ) > $D/issue-core-proof.json
|
||||
python3 scripts/workload_adoption_proof.py --live --source-root ~/target-revenue --observation $D/target-revenue-observation.json --receipt $D/target-revenue-proof.json
|
||||
python3 scripts/eso_adoption_readiness.py --draft argocd/railiance01/drafts/external-secrets.application.yaml --issue-core-proof $D/issue-core-proof.json --target-revenue-proof $D/target-revenue-proof.json | tee $D/readiness-r2.json
|
||||
# must print "ready_for_fresh_native_render_diff": true
|
||||
# b) fresh render + client-side diff (T05 method); credential data in diff output is masked by kubectl
|
||||
python3 -c "import yaml;print(yaml.safe_load(open('argocd/railiance01/drafts/external-secrets.application.yaml'))['spec']['source']['helm']['values'])" > /tmp/eso-values.yaml
|
||||
helm template external-secrets external-secrets --repo https://charts.external-secrets.io --version 0.16.1 -n external-secrets -f /tmp/eso-values.yaml > /tmp/eso-render.yaml
|
||||
ssh railiance01 "kubectl diff -f -" < /tmp/eso-render.yaml > $D/client-diff.txt; echo rc=$?
|
||||
# c) store baseline
|
||||
ssh railiance01 "kubectl get clustersecretstores -o custom-columns=NAME:.metadata.name,STATUS:.status.conditions[0].reason --no-headers" | tee $D/store-baseline-before.txt
|
||||
```
|
||||
|
||||
Go only if all of these hold:
|
||||
- the readiness gate is true;
|
||||
- the diff touches CRDs in metadata only (the protective annotation) and changes no CRD `spec`;
|
||||
- nothing is deleted or replaced;
|
||||
- the baseline shows every store `Valid` except `openbao-activity-core` and `openbao-email-connect` (`ValidationFailed`).
|
||||
|
||||
If the diff shows webhook `caBundle` drift, an agent adds `ignoreDifferences` for
|
||||
`ValidatingWebhookConfiguration` `/webhooks/0/clientConfig/caBundle` and `/webhooks/1/clientConfig/caBundle` and re-runs b.
|
||||
|
||||
## 2. Create the Application (an agent, after the gate is green)
|
||||
|
||||
The agent moves the draft to `argocd/railiance01/applications/external-secrets.application.yaml`,
|
||||
commits and pushes, runs `make argocd-pin-drift`, then creates the child only with
|
||||
`ssh railiance01 "kubectl apply --dry-run=server -f -" < <file>` followed by the same command without `--dry-run`.
|
||||
The root also carries other OutOfSync children. Creating the Application syncs nothing.
|
||||
|
||||
## 3. The founder's sync command (one command)
|
||||
|
||||
```bash
|
||||
ssh railiance01 "kubectl -n argocd patch application external-secrets --type merge -p '{\"operation\":{\"initiatedBy\":{\"username\":\"rpf-wp-0044-t06\"},\"sync\":{\"revision\":\"0.16.1\",\"prune\":false,\"syncOptions\":[\"ServerSideApply=true\"],\"syncStrategy\":{\"apply\":{\"force\":false}}}}}'"
|
||||
```
|
||||
|
||||
(Local double quotes; the remote shell receives the JSON inside single quotes. Prune off, force off, SSA.)
|
||||
|
||||
## 4. Post-sync checks
|
||||
|
||||
```bash
|
||||
ssh railiance01 "kubectl -n argocd get application external-secrets -o custom-columns=SYNC:.status.sync.status,HEALTH:.status.health.status,PHASE:.status.operationState.phase,REV:.status.sync.revision"
|
||||
# expect Synced Healthy Succeeded 0.16.1
|
||||
ssh railiance01 "kubectl -n external-secrets get deploy" # 3/3 available, no restarts beyond rollout
|
||||
ssh railiance01 "kubectl get crd -o name | grep -c external-secrets.io" # still 20
|
||||
ssh railiance01 "kubectl get clustersecretstores -o custom-columns=NAME:.metadata.name,STATUS:.status.conditions[0].reason --no-headers" > $D/store-baseline-after.txt
|
||||
diff $D/store-baseline-before.txt $D/store-baseline-after.txt && echo baseline-unchanged
|
||||
# ExternalSecret refresh sample (issue-core): force a refresh and confirm Ready
|
||||
ssh railiance01 "kubectl -n issue-core annotate externalsecret issue-core-runtime force-sync=\$(date +%s) --overwrite && sleep 20 && kubectl -n issue-core get externalsecret issue-core-runtime -o custom-columns=READY:.status.conditions[0].status,REASON:.status.conditions[0].reason"
|
||||
# expect True SecretSynced
|
||||
```
|
||||
|
||||
The agent records these as `docs/evidence/<date>-eso-argocd-adoption.json`, re-runs issue-core
|
||||
`verify-live`, and marks T06 done after the proving period.
|
||||
|
||||
## Rollback (abort owner: railiance-platform)
|
||||
|
||||
Never prune and never delete the Application with cascade. Revert the Application to the previously
|
||||
reviewed chart `0.16.1` values in Git (`git revert <adoption commit>`), re-apply the child, then
|
||||
run the same sync command as above. To stop Argo management without touching workloads, delete only
|
||||
the Application object. It has no finalizer, so no cascade happens, and the CRDs are protected anyway.
|
||||
|
||||
## Separate later step (not part of adoption)
|
||||
|
||||
Retire the stale `pending-upgrade` Helm release record (`sh.helm.release.v1.external-secrets.v*`)
|
||||
under its own reviewed cleanup. ArgoCD does not track it, and it must not be replaced silently.
|
||||
Loading…
Add table
Add a link
Reference in a new issue