Close verified incident task and finish local workplan loose ends
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e3c3-621b-7350-9f77-50a8d3ee7657
This commit is contained in:
parent
5781d34b3b
commit
debf981097
22 changed files with 1210 additions and 62 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# DRAFT for railiance01 (RPF-WP-0044). Not synced by any root: move to
|
||||
# ../applications/ only in this app's adoption task, with the founder's go-ahead.
|
||||
# No automated sync, no finalizer. targetRevision: chart version; T06 adds CRD Prune=false,Delete=false before merge.
|
||||
# No automated sync, no finalizer. CRDs survive Application pruning/deletion.
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
|
|
@ -21,6 +21,9 @@ spec:
|
|||
releaseName: external-secrets
|
||||
values: |
|
||||
installCRDs: true
|
||||
crds:
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-options: Prune=false,Delete=false
|
||||
serviceAccount:
|
||||
create: true
|
||||
name: external-secrets
|
||||
|
|
|
|||
62
docs/argocd-coulombcore-retirement.md
Normal file
62
docs/argocd-coulombcore-retirement.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Coulombcore ArgoCD retirement preparation
|
||||
|
||||
Existing owner task: RPF-WP-0044-T08. Prepared September 27, 2026; blocked
|
||||
pending a readable live inventory. No controller, application or workload was
|
||||
changed. This document is the phase C preparation within the existing workplan.
|
||||
|
||||
The host SSH lane works. Kubernetes returned Unauthorized for both the normal
|
||||
kubectl context and `sudo -n k3s kubectl --kubeconfig
|
||||
/etc/rancher/k3s/k3s.yaml get nodes`. The infrastructure/cluster owner must
|
||||
restore accepted read access; do not rotate cluster credentials or restart k3s
|
||||
as an incidental inventory fix. Current workload ownership cannot be inferred
|
||||
from the old manifests.
|
||||
|
||||
## Inventory and decision inputs
|
||||
|
||||
Capture node/cluster identity, ArgoCD deployments/statefulsets and installed
|
||||
version, Applications and AppProjects, each Application's destination, pinned
|
||||
revision, tracked resource set, hooks, automated sync and finalizers. Read only
|
||||
repository Secret metadata, never data. Identify external cluster destinations:
|
||||
an old controller can still manage a remote cluster. Search platform and tenant
|
||||
source for references to `argocd/applications/` and `argocd/bootstrap/`, including
|
||||
Make entry points, and match each live application to its accepting owner.
|
||||
|
||||
The railiance01 root uses `argocd/railiance01/applications`; the legacy root
|
||||
uses `argocd/applications`. Do not remove the legacy tree while the old controller
|
||||
can reconcile it with prune enabled. Keep evidence of each workload's current
|
||||
replicas, readiness and image before any retirement execution.
|
||||
|
||||
## Ordered execution after inventory and owner acceptance
|
||||
|
||||
1. Have the cluster owner pin the installed railiance01 ArgoCD version and
|
||||
reviewed resource requests in its canonical source. Inspect current requests;
|
||||
the original phase A BestEffort observation is historical, not a fresh check.
|
||||
2. Classify each old tracked resource: already adopted on railiance01, retained
|
||||
on coulombcore with another owner, or separately approved for retirement.
|
||||
An application name match does not prove matching cluster/resource identity.
|
||||
3. Freeze the old root and child reconciliation through the cluster owner's
|
||||
reviewed procedure. Confirm no running sync operation and no second writer.
|
||||
Preserve the old Application specs and controller configuration in protected
|
||||
recovery storage; repository credentials stay under existing custody.
|
||||
4. Detach only inventory-approved Application objects without cascading workload
|
||||
deletion. Review resource finalizers first; never delete the ArgoCD namespace
|
||||
or CRDs as a shortcut. Verify every retained workload is still healthy and
|
||||
each replacement owner can reconcile its accepted resource set.
|
||||
5. Disable the old controller through its actual installation owner. Prove it
|
||||
no longer reconciles and that no unrelated system uses its repository/auth
|
||||
resources. Revoke retired credentials only through their custody owners.
|
||||
6. Once the old controller is inert, remove the legacy source directories and
|
||||
retire or repoint their callers in one reviewed platform change. Render the
|
||||
railiance01 bootstrap and children and verify no legacy reference remains.
|
||||
|
||||
Stop for missing inventory, ambiguous tracking, active operations, unknown
|
||||
finalizers, missing acceptance or degraded retained workloads. Before detachment,
|
||||
rollback restores the recorded sync configuration. After replacement ownership,
|
||||
keep the old controller stopped until the replacement writer is explicitly
|
||||
suspended; rollback must never run two reconcilers against one workload. Package
|
||||
or data deletion needs its own exact approved disposition.
|
||||
|
||||
Completion evidence must include the inventory, accepting owners, source/caller
|
||||
changes, controller shutdown and retained-workload checks. T08's planning closure
|
||||
still requires the live read-only inventory. Execution remains with the existing
|
||||
cluster/infra owners; no new task or workplan is created here.
|
||||
492
docs/evidence/2026-09-27-argocd-loose-end-status.json
Normal file
492
docs/evidence/2026-09-27-argocd-loose-end-status.json
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
{
|
||||
"observed_at": "2026-09-27T16:53:28.268968+00:00",
|
||||
"applications": [
|
||||
{
|
||||
"name": "activity-core",
|
||||
"sync": {
|
||||
"comparedTo": {
|
||||
"destination": {
|
||||
"namespace": "activity-core",
|
||||
"server": "https://kubernetes.default.svc"
|
||||
},
|
||||
"source": {
|
||||
"path": "k8s/gitops",
|
||||
"repoURL": "https://forgejo.coulomb.social/coulomb/activity-core.git",
|
||||
"targetRevision": "a12f1169f9d130058ce767f5b26de0606997916c"
|
||||
}
|
||||
},
|
||||
"revision": "a12f1169f9d130058ce767f5b26de0606997916c",
|
||||
"status": "Synced"
|
||||
},
|
||||
"health": {
|
||||
"lastTransitionTime": "2026-09-27T14:06:22Z",
|
||||
"status": "Healthy"
|
||||
},
|
||||
"reconciledAt": "2026-09-27T16:50:21Z",
|
||||
"operation": {
|
||||
"phase": "Succeeded",
|
||||
"startedAt": "2026-09-27T14:06:19Z",
|
||||
"finishedAt": "2026-09-27T14:06:20Z"
|
||||
},
|
||||
"automated": null,
|
||||
"conditions": [],
|
||||
"resources": [
|
||||
{
|
||||
"kind": "ConfigMap",
|
||||
"name": "actcore-external-activity-definitions",
|
||||
"namespace": "activity-core",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "ConfigMap",
|
||||
"name": "actcore-ops-service-inventory",
|
||||
"namespace": "activity-core",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "ConfigMap",
|
||||
"name": "actcore-report-schemas",
|
||||
"namespace": "activity-core",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "ConfigMap",
|
||||
"name": "actcore-runtime-config",
|
||||
"namespace": "activity-core",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"name": "actcore-api",
|
||||
"namespace": "activity-core",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"name": "actcore-worker-metrics",
|
||||
"namespace": "activity-core",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "apps",
|
||||
"kind": "Deployment",
|
||||
"name": "actcore-api",
|
||||
"namespace": "activity-core",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "apps",
|
||||
"kind": "Deployment",
|
||||
"name": "actcore-event-router",
|
||||
"namespace": "activity-core",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "apps",
|
||||
"kind": "Deployment",
|
||||
"name": "actcore-worker",
|
||||
"namespace": "activity-core",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bao-notice",
|
||||
"sync": {
|
||||
"comparedTo": {
|
||||
"destination": {
|
||||
"namespace": "bao-notice",
|
||||
"server": "https://kubernetes.default.svc"
|
||||
},
|
||||
"source": {
|
||||
"path": "argocd/platform-addons/bao-notice",
|
||||
"repoURL": "https://forgejo.coulomb.social/coulomb/railiance-platform.git",
|
||||
"targetRevision": "9ee20967ca7b50a8926c99ae86fa027f8bfb0fa3"
|
||||
}
|
||||
},
|
||||
"revision": "9ee20967ca7b50a8926c99ae86fa027f8bfb0fa3",
|
||||
"status": "OutOfSync"
|
||||
},
|
||||
"health": {
|
||||
"lastTransitionTime": "2026-09-23T22:56:40Z",
|
||||
"status": "Healthy"
|
||||
},
|
||||
"reconciledAt": "2026-09-27T16:52:12Z",
|
||||
"operation": {
|
||||
"phase": "Succeeded",
|
||||
"startedAt": "2026-09-23T22:56:34Z",
|
||||
"finishedAt": "2026-09-23T22:56:36Z"
|
||||
},
|
||||
"automated": null,
|
||||
"conditions": [
|
||||
{
|
||||
"lastTransitionTime": "2026-09-23T22:55:19Z",
|
||||
"message": "Application has 1 orphaned resources",
|
||||
"type": "OrphanedResourceWarning"
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"kind": "ConfigMap",
|
||||
"name": "bao-notice-conf-4f5g9kc7c2",
|
||||
"namespace": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "ConfigMap",
|
||||
"name": "bao-notice-conf-dg4hmf2dg4",
|
||||
"namespace": "bao-notice",
|
||||
"requiresPruning": true,
|
||||
"status": "OutOfSync",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "ConfigMap",
|
||||
"name": "bao-notice-html-6mm6h6mgkf",
|
||||
"namespace": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "Namespace",
|
||||
"name": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "Service",
|
||||
"name": "bao-notice",
|
||||
"namespace": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "apps",
|
||||
"kind": "Deployment",
|
||||
"name": "bao-notice",
|
||||
"namespace": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "networking.k8s.io",
|
||||
"kind": "Ingress",
|
||||
"name": "bao-notice",
|
||||
"namespace": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "networking.k8s.io",
|
||||
"kind": "Ingress",
|
||||
"name": "bao-notice-http-redirect",
|
||||
"namespace": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "networking.k8s.io",
|
||||
"kind": "NetworkPolicy",
|
||||
"name": "bao-notice-acme-solver",
|
||||
"namespace": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "networking.k8s.io",
|
||||
"kind": "NetworkPolicy",
|
||||
"name": "bao-notice-isolation",
|
||||
"namespace": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "traefik.io",
|
||||
"kind": "Middleware",
|
||||
"name": "redirect-https",
|
||||
"namespace": "bao-notice",
|
||||
"status": "Synced",
|
||||
"version": "v1alpha1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eso-token-renewer",
|
||||
"sync": {
|
||||
"comparedTo": {
|
||||
"destination": {
|
||||
"namespace": "external-secrets",
|
||||
"server": "https://kubernetes.default.svc"
|
||||
},
|
||||
"source": {
|
||||
"path": "argocd/platform-addons/eso-token-renewer",
|
||||
"repoURL": "https://forgejo.coulomb.social/coulomb/railiance-platform.git",
|
||||
"targetRevision": "b2ebe108495c4d06ebb6ca33893ea4a2a23c9725"
|
||||
}
|
||||
},
|
||||
"revision": "b2ebe108495c4d06ebb6ca33893ea4a2a23c9725",
|
||||
"status": "Synced"
|
||||
},
|
||||
"health": {
|
||||
"lastTransitionTime": "2026-09-23T22:38:19Z",
|
||||
"status": "Healthy"
|
||||
},
|
||||
"reconciledAt": "2026-09-27T16:50:17Z",
|
||||
"operation": {
|
||||
"phase": "Succeeded",
|
||||
"startedAt": "2026-09-23T22:38:19Z",
|
||||
"finishedAt": "2026-09-23T22:38:19Z"
|
||||
},
|
||||
"automated": null,
|
||||
"conditions": [
|
||||
{
|
||||
"lastTransitionTime": "2026-09-23T22:37:58Z",
|
||||
"message": "Application has 28 orphaned resources",
|
||||
"type": "OrphanedResourceWarning"
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"kind": "ConfigMap",
|
||||
"name": "eso-token-renewer-worker-5c86dt7fm7",
|
||||
"namespace": "external-secrets",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"kind": "ServiceAccount",
|
||||
"name": "eso-token-renewer",
|
||||
"namespace": "external-secrets",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "batch",
|
||||
"kind": "CronJob",
|
||||
"name": "eso-token-renewer",
|
||||
"namespace": "external-secrets",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "openbao-secretstore",
|
||||
"sync": {
|
||||
"comparedTo": {
|
||||
"destination": {
|
||||
"namespace": "external-secrets",
|
||||
"server": "https://kubernetes.default.svc"
|
||||
},
|
||||
"source": {
|
||||
"path": "argocd/platform-addons/openbao-secretstore",
|
||||
"repoURL": "https://forgejo.coulomb.social/coulomb/railiance-platform.git",
|
||||
"targetRevision": "d2dbc19c254247652c49fda8721c80d53bca206a"
|
||||
}
|
||||
},
|
||||
"revision": "d2dbc19c254247652c49fda8721c80d53bca206a",
|
||||
"status": "Synced"
|
||||
},
|
||||
"health": {
|
||||
"lastTransitionTime": "2026-09-21T17:09:00Z",
|
||||
"status": "Healthy"
|
||||
},
|
||||
"reconciledAt": "2026-09-27T16:52:14Z",
|
||||
"operation": {
|
||||
"phase": "Succeeded",
|
||||
"startedAt": "2026-09-21T17:09:16Z",
|
||||
"finishedAt": "2026-09-21T17:09:18Z"
|
||||
},
|
||||
"automated": null,
|
||||
"conditions": [
|
||||
{
|
||||
"lastTransitionTime": "2026-09-23T18:14:58Z",
|
||||
"message": "Application has 28 orphaned resources",
|
||||
"type": "OrphanedResourceWarning"
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"group": "external-secrets.io",
|
||||
"kind": "ClusterSecretStore",
|
||||
"name": "openbao",
|
||||
"status": "Synced",
|
||||
"version": "v1beta1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "railiance-apps-root",
|
||||
"sync": {
|
||||
"comparedTo": {
|
||||
"destination": {
|
||||
"namespace": "argocd",
|
||||
"server": "https://kubernetes.default.svc"
|
||||
},
|
||||
"source": {
|
||||
"path": "argocd/railiance01/applications",
|
||||
"repoURL": "https://forgejo.coulomb.social/coulomb/railiance-platform.git",
|
||||
"targetRevision": "main"
|
||||
}
|
||||
},
|
||||
"revision": "5781d34b3b9a6e3779b913de200f0eaf63cabacd",
|
||||
"status": "Synced"
|
||||
},
|
||||
"health": {
|
||||
"lastTransitionTime": "2026-09-21T17:08:13Z",
|
||||
"status": "Healthy"
|
||||
},
|
||||
"reconciledAt": "2026-09-27T16:51:31Z",
|
||||
"operation": {
|
||||
"phase": "Succeeded",
|
||||
"startedAt": "2026-09-27T14:05:47Z",
|
||||
"finishedAt": "2026-09-27T14:05:49Z"
|
||||
},
|
||||
"automated": null,
|
||||
"conditions": [
|
||||
{
|
||||
"lastTransitionTime": "2026-09-21T17:08:13Z",
|
||||
"message": "Application has 1 orphaned resources",
|
||||
"type": "OrphanedResourceWarning"
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"group": "argoproj.io",
|
||||
"kind": "Application",
|
||||
"name": "activity-core",
|
||||
"namespace": "argocd",
|
||||
"status": "Synced",
|
||||
"version": "v1alpha1"
|
||||
},
|
||||
{
|
||||
"group": "argoproj.io",
|
||||
"kind": "Application",
|
||||
"name": "bao-notice",
|
||||
"namespace": "argocd",
|
||||
"status": "Synced",
|
||||
"syncWave": 10,
|
||||
"version": "v1alpha1"
|
||||
},
|
||||
{
|
||||
"group": "argoproj.io",
|
||||
"kind": "Application",
|
||||
"name": "eso-token-renewer",
|
||||
"namespace": "argocd",
|
||||
"status": "Synced",
|
||||
"syncWave": 2,
|
||||
"version": "v1alpha1"
|
||||
},
|
||||
{
|
||||
"group": "argoproj.io",
|
||||
"kind": "Application",
|
||||
"name": "openbao-secretstore",
|
||||
"namespace": "argocd",
|
||||
"status": "Synced",
|
||||
"syncWave": 1,
|
||||
"version": "v1alpha1"
|
||||
},
|
||||
{
|
||||
"group": "argoproj.io",
|
||||
"kind": "Application",
|
||||
"name": "target-revenue",
|
||||
"namespace": "argocd",
|
||||
"status": "Synced",
|
||||
"syncWave": 10,
|
||||
"version": "v1alpha1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "target-revenue",
|
||||
"sync": {
|
||||
"comparedTo": {
|
||||
"destination": {
|
||||
"namespace": "target-revenue",
|
||||
"server": "https://kubernetes.default.svc"
|
||||
},
|
||||
"source": {
|
||||
"path": "k8s/railiance",
|
||||
"repoURL": "https://forgejo.coulomb.social/coulomb/target-revenue.git",
|
||||
"targetRevision": "f1109d54eeda9f187daa215cf1c7163610d35d0a"
|
||||
}
|
||||
},
|
||||
"revision": "f1109d54eeda9f187daa215cf1c7163610d35d0a",
|
||||
"status": "Synced"
|
||||
},
|
||||
"health": {
|
||||
"lastTransitionTime": "2026-09-21T17:13:49Z",
|
||||
"status": "Healthy"
|
||||
},
|
||||
"reconciledAt": "2026-09-27T16:50:17Z",
|
||||
"operation": {
|
||||
"phase": "Succeeded",
|
||||
"startedAt": "2026-09-21T17:14:01Z",
|
||||
"finishedAt": "2026-09-21T17:14:10Z"
|
||||
},
|
||||
"automated": null,
|
||||
"conditions": [
|
||||
{
|
||||
"lastTransitionTime": "2026-09-21T17:13:49Z",
|
||||
"message": "Application has 5 orphaned resources",
|
||||
"type": "OrphanedResourceWarning"
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"kind": "Service",
|
||||
"name": "target-revenue",
|
||||
"namespace": "target-revenue",
|
||||
"status": "Synced",
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "apps",
|
||||
"kind": "Deployment",
|
||||
"name": "target-revenue",
|
||||
"namespace": "target-revenue",
|
||||
"status": "Synced",
|
||||
"syncWave": 3,
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "external-secrets.io",
|
||||
"kind": "ExternalSecret",
|
||||
"name": "target-revenue-runtime",
|
||||
"namespace": "target-revenue",
|
||||
"status": "Synced",
|
||||
"version": "v1beta1"
|
||||
},
|
||||
{
|
||||
"group": "networking.k8s.io",
|
||||
"kind": "Ingress",
|
||||
"name": "target-revenue",
|
||||
"namespace": "target-revenue",
|
||||
"status": "Synced",
|
||||
"syncWave": 4,
|
||||
"version": "v1"
|
||||
},
|
||||
{
|
||||
"group": "postgresql.cnpg.io",
|
||||
"kind": "Cluster",
|
||||
"name": "target-revenue-pg",
|
||||
"namespace": "target-revenue",
|
||||
"status": "Synced",
|
||||
"syncWave": -2,
|
||||
"version": "v1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"coulombcore_inventory": "unavailable: Kubernetes Unauthorized, including explicit local k3s kubeconfig; no credential or controller mutation"
|
||||
}
|
||||
12
docs/evidence/2026-09-27-eso-adoption-preparation.json
Normal file
12
docs/evidence/2026-09-27-eso-adoption-preparation.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"observed_at": "2026-09-27T16:59:10.112128+00:00",
|
||||
"chart": "0.16.1",
|
||||
"draft_sha256": "a0b349cddd90aa707f080efd8556c8379d5b178d93b4c9e408f3b7f439bbf064",
|
||||
"render_sha256": "55236645afc9f2d9d376c28e73aed70bd31727d0e6f166664b3ebd568d5f136f",
|
||||
"objects": 39,
|
||||
"protected_crds": 20,
|
||||
"server_diff_exit_code": 1,
|
||||
"applied": false,
|
||||
"diff_summary": "Exactly 20 CRD metadata annotation additions; no spec, workload or other object changes",
|
||||
"diff_sha256": "3c34ad673fc374442adc13eeaf17c5216fce7b904103e63014d10e4ba6272965"
|
||||
}
|
||||
33
docs/evidence/2026-09-27-keycape-incident-owner-return.json
Normal file
33
docs/evidence/2026-09-27-keycape-incident-owner-return.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"schema": "platform.incident-owner-return.v1",
|
||||
"reviewed_at": "2026-09-27T17:01:20.402024+00:00",
|
||||
"task": "RPF-WP-0027-T05",
|
||||
"sources": [
|
||||
{
|
||||
"repository": "net-kingdom",
|
||||
"path": "workplans/NK-WP-0033-keycape-secret-exposure-rotation.md",
|
||||
"commit": "1da6e5457ad86fff1173bd2ff6174d70719b487d",
|
||||
"sha256": "8268aa86f7fa9f2a3848adfe2dc3022bcf2e9dc9197328993445f4138a40e513"
|
||||
},
|
||||
{
|
||||
"repository": "key-cape",
|
||||
"path": "workplans/KEY-WP-0011-live-secret-exposure-recovery.md",
|
||||
"commit": "6a996bd71e5e36d7483e7a79b3301bd895907644",
|
||||
"sha256": "3c5458180fe81a04e357f8db737e4287f79640b5ab02682bcadc595b73f846cd"
|
||||
}
|
||||
],
|
||||
"operator_ruling_date": "2026-09-23",
|
||||
"operator": "Bernd Worsch",
|
||||
"owner_check": "reconcile-lldap-resolver-live.sh --check --predecessor-unavailable",
|
||||
"owner_receipt": {
|
||||
"resolver_lookup": "PASS",
|
||||
"privacyidea_mfa": "PASS",
|
||||
"predecessor_denial": "NOT-PROVEN",
|
||||
"readiness": "PASS",
|
||||
"health": "PASS",
|
||||
"cleanup": "PASS"
|
||||
},
|
||||
"disposition": "Operator explicitly accepted the August 27 observations; unrecoverable predecessor is not a required new test. NetKingdom marks incident closed.",
|
||||
"live_action_performed_in_this_review": false,
|
||||
"custody_handoff_complete": false
|
||||
}
|
||||
192
docs/evidence/2026-09-27-service-assurance.json
Normal file
192
docs/evidence/2026-09-27-service-assurance.json
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
{
|
||||
"observation": {
|
||||
"schema": "railiance-platform.observation.v1",
|
||||
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
|
||||
"captured_at": "2026-09-27T16:53:44.173824+00:00",
|
||||
"signals": {
|
||||
"apps-pg.ready": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:28.888062+00:00"
|
||||
},
|
||||
"apps-pg.backup": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T02:15:16Z"
|
||||
},
|
||||
"apps-pg.wal": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:28.888098+00:00"
|
||||
},
|
||||
"apps-pg.headroom": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:16Z"
|
||||
},
|
||||
"platform-pg.ready": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:32.163508+00:00"
|
||||
},
|
||||
"platform-pg.backup": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T02:15:18Z"
|
||||
},
|
||||
"platform-pg.wal": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:32.163550+00:00"
|
||||
},
|
||||
"platform-pg.headroom": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:32Z"
|
||||
},
|
||||
"platform-pg-2.ready": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:35.169803+00:00"
|
||||
},
|
||||
"platform-pg-2.backup": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T02:15:14Z"
|
||||
},
|
||||
"platform-pg-2.wal": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:35.169827+00:00"
|
||||
},
|
||||
"platform-pg-2.headroom": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:22Z"
|
||||
},
|
||||
"openbao.seal": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:42.333471+00:00"
|
||||
},
|
||||
"eso.ready": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:53:43.311315+00:00"
|
||||
},
|
||||
"eso.refresh": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T16:06:45Z"
|
||||
},
|
||||
"eso.token-renewal": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-27T02:40:09Z"
|
||||
},
|
||||
"apps-pg.restore": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-05T22:30:45.208512+00:00"
|
||||
},
|
||||
"forgejo-db.restore": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-09-05T22:55:54.893587+00:00"
|
||||
},
|
||||
"openbao.snapshot": {
|
||||
"result": "pass",
|
||||
"observed_at": "2026-08-22T22:29:21Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
"evaluation": {
|
||||
"schema": "railiance-platform.assurance-signal.v1",
|
||||
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
|
||||
"evaluated_at": "2026-09-27T16:53:44.173824+00:00",
|
||||
"signals": {
|
||||
"apps-pg.ready": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"apps-pg.backup": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"apps-pg.wal": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"apps-pg.restore": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"apps-pg.headroom": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"platform-pg.ready": {
|
||||
"state": "healthy",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"platform-pg.backup": {
|
||||
"state": "healthy",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"platform-pg.wal": {
|
||||
"state": "healthy",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"platform-pg.restore": {
|
||||
"state": "missing",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"platform-pg.headroom": {
|
||||
"state": "healthy",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"platform-pg-2.ready": {
|
||||
"state": "healthy",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"platform-pg-2.backup": {
|
||||
"state": "healthy",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"platform-pg-2.wal": {
|
||||
"state": "healthy",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"platform-pg-2.restore": {
|
||||
"state": "missing",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"platform-pg-2.headroom": {
|
||||
"state": "healthy",
|
||||
"owner": "rapp-postgres"
|
||||
},
|
||||
"openbao.seal": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"openbao.snapshot": {
|
||||
"state": "stale",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"openbao.restore": {
|
||||
"state": "missing",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"offsite.upload": {
|
||||
"state": "missing",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"offsite.restore": {
|
||||
"state": "missing",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"eso.ready": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"eso.refresh": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"forgejo-db.restore": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
},
|
||||
"eso.token-renewal": {
|
||||
"state": "healthy",
|
||||
"owner": "railiance-platform"
|
||||
}
|
||||
},
|
||||
"transport": "unmonitored",
|
||||
"guarantees": "unsupported",
|
||||
"threshold_status": "local-diagnostic-only",
|
||||
"healthy": false
|
||||
}
|
||||
}
|
||||
|
|
@ -3,8 +3,8 @@
|
|||
Historical resolver lanes: **draft / blocked**.
|
||||
KeyCape factor service lane: **active**, established and verified 2026-09-13 (below).
|
||||
Incident: `KEYCAPE-EXPOSURE-20260823-01`
|
||||
Consumer procedure: NetKingdom `NK-WP-0033`, resolver reconciliation revision
|
||||
`eec7007` / checkout `f2e578c`
|
||||
Consumer procedure: NetKingdom `NK-WP-0033`; latest attended check used
|
||||
checkout `6096c395` (script `4a38511`) on 2026-09-23.
|
||||
|
||||
This document defines the Railiance-side contract without containing or
|
||||
deriving any credential value. It is not an authorization to fetch, export,
|
||||
|
|
@ -49,6 +49,17 @@ Operator decision 2026-09-15: leave both historical resolver lanes blocked.
|
|||
Do not invent mount, path, or field names. The KeyCape factor service lane
|
||||
below is separate and does not close this gate.
|
||||
|
||||
September 27 evidence review: NetKingdom's September 23 operator ruling and
|
||||
green attended `--check --predecessor-unavailable` receipt close the incident
|
||||
verification obligation (RPF-WP-0027-T05). The predecessor remains NOT-PROVEN;
|
||||
the operator explicitly accepted its unavailable disposition. The owner records
|
||||
human custody at `operators/lldap/admin` and `operators/privacyidea/pi-admin`,
|
||||
including KV v2 LLDAP version 1 and withheld delete under `operator-custody`.
|
||||
These are confirmed owner coordinates, but they do not by themselves establish
|
||||
either historical route's complete field, auth, expiry and handoff contract.
|
||||
T03/T06 and the non-resolvable historical routes therefore remain blocked.
|
||||
See `docs/evidence/2026-09-27-keycape-incident-owner-return.json`.
|
||||
|
||||
## KeyCape factor service lane — authorized setup, 2026-09-13
|
||||
|
||||
RPF-WP-0040 / CCR-2026-0023 establish a new dedicated service lane. The user,
|
||||
|
|
|
|||
|
|
@ -61,13 +61,12 @@ CronJob status timestamps only. It fails when a newer scheduled run has not
|
|||
succeeded within an hour, and it goes stale after 36h. The tokens lapse after
|
||||
7 days without renewal.
|
||||
|
||||
The following remain missing until a native value-safe adapter and acceptance
|
||||
exist: validated isolated restore receipts,
|
||||
OpenBao snapshot/restore proof, and offsite upload/restore receipts. Missing
|
||||
adapters are not inferred healthy from pod readiness. The local producer is
|
||||
not the Q2 standard; railiance-telemetry has no implemented receiving contract
|
||||
in the reviewed checkout. Integration, routing and scheduled delivery remain
|
||||
T04, and no notification was sent during implementation.
|
||||
Current gaps include accepted platform-pg/platform-pg-2 and OpenBao isolated
|
||||
restore samples, fresh OpenBao snapshots, and dated full-archive receipts.
|
||||
Missing evidence is not inferred healthy from pod readiness. RTEL-WP-0002
|
||||
implements the Q2 reference contract and local delivery tests; its T04 still
|
||||
owns production mapping, recipient and controlled failure/absence acceptance.
|
||||
Integration, routing and scheduled delivery remain T04 here.
|
||||
|
||||
## Service records and evidence inventory
|
||||
|
||||
|
|
@ -87,7 +86,7 @@ provider invalidation/replacement recovery for the shared offsite lane.
|
|||
| OpenBao snapshot | WARDEN-WP-0027 preparation receipt, 2026-08-23 | Snapshot/encrypted off-host preparation, not isolated restore |
|
||||
| OpenBao restore | Existing `openbao-validate-restore-evidence.sh` and package procedure | Example receipt cannot pass as a fresh execution |
|
||||
| Recovery exercise | RPF-WP-0015-T02/T03 | Separate windows, synthetic driver/quorum and abort operator required |
|
||||
| Logical/Forgejo offsite | activity-core backup definitions, existing helper/runbooks | No new upload/restore performed; RPF-WP-0029 remains open |
|
||||
| Logical/Forgejo offsite | activity-core backup definitions, existing helper/runbooks | WP-0029 is finished; WP-0038 retains recurring primary/secondary activation |
|
||||
|
||||
## Admission and disclosure drift
|
||||
|
||||
|
|
@ -134,8 +133,26 @@ Decryption now retains `platform.forgejo-primary-decryption.v1` and its own
|
|||
operation times; older decryption receipts used the transfer schema through an
|
||||
overwrite bug. The restore tool explicitly accepts both forms, with verified
|
||||
hash/decryption flags. Existing historical receipts are unchanged. These producer
|
||||
fixes enable future dated archive evidence; automatic archive adapters, fresh
|
||||
end-to-end receipts and recurring execution are still pending.
|
||||
fixes enable dated archive evidence. The full primary archive adapter is now
|
||||
implemented; fresh end-to-end receipts and recurring execution remain pending.
|
||||
|
||||
For `offsite.upload`, add a reviewed entry with `signal`, `path` and `sha256`
|
||||
to the recovery index. It must name a full-profile Scaleway archive transfer
|
||||
with completed multipart upload, version-pinned GET, matching byte counts/hash,
|
||||
the application-archive destination and ordered timezone-aware timestamps.
|
||||
For `offsite.restore`, the entry additionally names `decryption` and `transfer`,
|
||||
each with `path` and `sha256`. The restore must attest database import, application
|
||||
health, repository verification, all package blobs and successful scratch cleanup.
|
||||
The receipt hashes, ciphertext identity, destination, profile and operation order
|
||||
must match across all three receipts. Only the distinct decryption schema is
|
||||
accepted for automatic assurance. Essentials and Nextcloud-only proofs cannot
|
||||
substitute for this primary full-application recovery signal. Other supported
|
||||
services still need their own evidence; one Forgejo receipt does not close T03.
|
||||
|
||||
No historical index entry was added: the September 6 archive receipts lack
|
||||
operation timestamps. They remain manual evidence. Tests use synthetic receipt
|
||||
chains and prove expiry, provenance rejection and rejection of the real undated
|
||||
receipt; those fixtures do not assert a new live recovery.
|
||||
|
||||
The OpenBao snapshot adapter also accepts the reviewed, hash-pinned receipt in
|
||||
`reviews/`. It requires the expected source cluster identity, encrypted off-host
|
||||
|
|
|
|||
73
history/2026-09-27-loose-end-review.md
Normal file
73
history/2026-09-27-loose-end-review.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Loose-end review — September 27, 2026
|
||||
|
||||
Reviewed every unfinished source workplan, terminal/archived task states,
|
||||
the empty unread inbox and human-needed Hub records, with current owner sources
|
||||
and read-only cluster evidence. No new workplan or task was created. Historical
|
||||
`cancelled` task statuses in the superseded baseline are terminal, not open work.
|
||||
Retired Hub aliases are not additional source obligations.
|
||||
|
||||
## Completed work
|
||||
|
||||
- Closed RPF-WP-0027-T05 from the newer NK-WP-0033 operator ruling and attended
|
||||
September 23 receipt. KEY-WP-0011 already records the other credential classes.
|
||||
Predecessor denial remains NOT-PROVEN; the operator accepted the unavailable
|
||||
predecessor's disposition explicitly. Source commits and hashes are in
|
||||
`docs/evidence/2026-09-27-keycape-incident-owner-return.json`. No rotation was
|
||||
repeated. Historical custody routing still needs its complete accepted contract.
|
||||
- Implemented the WP-0036-T03 full-primary archive assurance adapter. It requires
|
||||
an ordered, hash-bound transfer/decryption/recovery chain, verified versioned
|
||||
download, full profile, application/database/repository/package proof and cleanup.
|
||||
New primary receipts preserve the archive profile. Undated historical receipts,
|
||||
essentials-only restores, failures and mismatched chains cannot pass. No fresh
|
||||
live archive receipt or recurring cadence is claimed by these fixture tests.
|
||||
- Completed WP-0044-T06 repository preparation: all 20 ESO CRDs receive
|
||||
`Prune=false,Delete=false` in the inactive draft. Chart 0.16.1 renders 39 objects;
|
||||
server-side diff contains exactly those 20 annotation additions and no spec
|
||||
changes. Evidence: `docs/evidence/2026-09-27-eso-adoption-preparation.json`.
|
||||
- Prepared the concrete phase C retirement sequence under WP-0044-T08 at
|
||||
`docs/argocd-coulombcore-retirement.md`. Live inventory still cannot finish:
|
||||
coulombcore SSH succeeds but Kubernetes returns Unauthorized, including with
|
||||
the explicit host-local k3s kubeconfig. No credential rotation or restart was
|
||||
attempted as a workaround.
|
||||
- Corrected the current index, custody incident status and stale assurance
|
||||
documentation. Platform accepts policy-nexus's proposed chart/values ownership
|
||||
split in principle; railiance-apps still must accept and publish its values
|
||||
path/revision. No cross-owner agreement is fabricated.
|
||||
|
||||
## Live observations and remaining gates
|
||||
|
||||
`docs/evidence/2026-09-27-argocd-loose-end-status.json` records six Applications.
|
||||
Openbao-secretstore and target-revenue are Synced/Healthy, with September 21
|
||||
healthy transition times; their original observation periods have elapsed.
|
||||
Their remaining promotion/owner gates now show `wait` instead of `progress`.
|
||||
All 25 ClusterSecretStores are Valid and issue-core-runtime is SecretSynced.
|
||||
Activity-core is Synced/Healthy; its required observation cannot end before
|
||||
September 28 at 16:06:22 Berlin. Its scoped broker/admission remains separate.
|
||||
Bao-notice is Healthy but OutOfSync; this review did not sync unrelated apps.
|
||||
|
||||
`docs/evidence/2026-09-27-service-assurance.json` preserves the current observation
|
||||
and evaluation: 18 healthy, five missing and one stale signal. The stale receipt
|
||||
is the old OpenBao snapshot. Missing signals are platform-pg/platform-pg-2 restore,
|
||||
OpenBao restore and offsite upload/restore. The archive adapter is ready for fresh
|
||||
reviewed receipts; the existing undated September 6 evidence is not re-dated.
|
||||
Transport remains unmonitored. Q2 has a local contract and selected rapp-telemetry
|
||||
package; RTEL-WP-0002-T04 still owns actual mapping/delivery/absence acceptance.
|
||||
|
||||
All eight unfinished workplans now explicitly say `blocked`; their 23 remaining
|
||||
tasks say `wait`. They retain the concrete unblocks in their September 27 entries.
|
||||
The open work is dominated by native owner acceptance, protected attended actions,
|
||||
fresh recovery evidence, inventory access and the time-bound observation gate.
|
||||
No blanket approval request, duplicate task, new schedule, credential read,
|
||||
backup expiration, production rollout or owner message was introduced.
|
||||
|
||||
## Validation
|
||||
|
||||
The repository suite passed 418 tests with one skip before the additional three
|
||||
profile-propagation cases. The final focused archive suite passed all 70 tests,
|
||||
including those three cases. Admission matches the reviewed baseline; live metadata capture succeeds.
|
||||
The assurance evaluator correctly exits nonzero for the disclosed missing/stale
|
||||
evidence. ESO render assertions and the exact metadata-only diff passed.
|
||||
|
||||
Commit and Repo Manager synchronization receipts are recorded in the session
|
||||
close progress event. The generated legacy aliases remain WP-0036-T06's scoped
|
||||
projection-owner dependency and are not silently repaired by changing UUIDs.
|
||||
|
|
@ -8,6 +8,82 @@ from service_assurance import timestamp
|
|||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def pinned_receipt(entry, root):
|
||||
path = (root / entry['path']).resolve()
|
||||
if not path.is_relative_to((root / 'docs/evidence').resolve()):
|
||||
raise ValueError('receipt outside evidence directory')
|
||||
raw = path.read_bytes()
|
||||
if hashlib.sha256(raw).hexdigest() != entry['sha256']:
|
||||
raise ValueError('receipt drift')
|
||||
return json.loads(raw)
|
||||
|
||||
|
||||
def operation_times(receipt, now):
|
||||
start, finish = (timestamp(receipt[key]) for key in ('started_at', 'finished_at'))
|
||||
if not start <= finish <= now:
|
||||
raise ValueError('invalid receipt chronology')
|
||||
return start, finish
|
||||
|
||||
|
||||
def primary_archive(receipt, now):
|
||||
"""Accept only explicit full primary transfers, including a verified versioned GET."""
|
||||
operation_times(receipt, now)
|
||||
if (receipt['schema'] != 'platform.forgejo-primary-archive.v1'
|
||||
or receipt['status'] != 'primary_fetched_pending_application_restore'
|
||||
or receipt['stage'] != 'transfer_verified'
|
||||
or receipt['archive_profile'] != 'full'
|
||||
or not receipt['destination'].startswith(
|
||||
's3://railiance-platform-pg-backup/platform-pg/application-archives/forgejo/')
|
||||
or not re.fullmatch(r'[0-9a-f]{64}', receipt['ciphertext_sha256'])
|
||||
or not all(receipt.get(key) is True for key in
|
||||
('multipart_completed', 'version_pinned', 'download_hash_matches'))
|
||||
or type(receipt['ciphertext_bytes']) is not int
|
||||
or receipt['ciphertext_bytes'] <= 0
|
||||
or any(type(receipt[key]) is not int or receipt[key] != receipt['ciphertext_bytes']
|
||||
for key in ('uploaded_bytes', 'downloaded_bytes'))):
|
||||
raise ValueError('primary archive not accepted')
|
||||
|
||||
|
||||
def archive_signal(entry, receipt, now, root):
|
||||
if entry['signal'] == 'offsite.upload':
|
||||
primary_archive(receipt, now)
|
||||
else:
|
||||
start, _ = operation_times(receipt, now)
|
||||
if (receipt['schema'] != 'platform.forgejo-isolated-restore.v1'
|
||||
or receipt['status'] != 'restored'
|
||||
or receipt['archive_profile'] != 'full'
|
||||
or receipt['source_provider'] != 'Scaleway'
|
||||
or receipt['stage'] != 'package_blob_recovery'
|
||||
or not all(receipt.get(key) is True for key in
|
||||
('database_import', 'application_health', 'cleanup'))
|
||||
or not receipt['repositories_verified']
|
||||
or type(receipt['package_blobs_verified']) is not int
|
||||
or receipt['package_blobs_verified'] < 0
|
||||
or type(receipt['database_counts']['package_blobs']) is not int
|
||||
or receipt['package_blobs_verified'] != receipt['database_counts']['package_blobs']):
|
||||
raise ValueError('full application recovery not accepted')
|
||||
decryption = pinned_receipt(entry['decryption'], root)
|
||||
transfer = pinned_receipt(entry['transfer'], root)
|
||||
primary_archive(transfer, now)
|
||||
decrypt_start, decrypt_finish = operation_times(decryption, now)
|
||||
if (decryption['schema'] != 'platform.forgejo-primary-decryption.v1'
|
||||
or decryption['status'] != 'primary_fetched_pending_application_restore'
|
||||
or decryption['archive_profile'] != 'full'
|
||||
or decryption['decrypted'] is not True
|
||||
or decryption['download_hash_matches'] is not True
|
||||
or not re.fullmatch(r'[0-9a-f]{64}', decryption['plaintext_sha256'])
|
||||
or receipt['transfer_receipt_sha256'] != entry['decryption']['sha256']
|
||||
or decryption['transfer_receipt_sha256'] != entry['transfer']['sha256']
|
||||
or not timestamp(transfer['finished_at']) <= decrypt_start <= decrypt_finish <= start
|
||||
or receipt['offsite_artifact'] != transfer['destination']
|
||||
or decryption['destination'] != transfer['destination']
|
||||
or decryption['ciphertext_bytes'] != transfer['ciphertext_bytes']
|
||||
or any(r['ciphertext_sha256'] != transfer['ciphertext_sha256']
|
||||
for r in (receipt, decryption))):
|
||||
raise ValueError('recovery provenance mismatch')
|
||||
return {'result': 'pass', 'observed_at': receipt['finished_at']}
|
||||
|
||||
|
||||
def recovery_signals(now, root=ROOT):
|
||||
index = json.loads((root / 'assurance/recovery-evidence.json').read_text())
|
||||
if index['schema'] != 'railiance-platform.recovery-evidence.v1':
|
||||
|
|
@ -15,10 +91,14 @@ def recovery_signals(now, root=ROOT):
|
|||
signals = {}
|
||||
for entry in index['receipts']:
|
||||
signal = entry['signal']
|
||||
if signal in signals or signal not in ('apps-pg.restore', 'forgejo-db.restore', 'openbao.snapshot'):
|
||||
if signal in signals or signal not in ('apps-pg.restore', 'forgejo-db.restore',
|
||||
'openbao.snapshot', 'offsite.upload', 'offsite.restore'):
|
||||
raise ValueError('unexpected recovery signal')
|
||||
sample = {'result': 'unavailable', 'observed_at': now.isoformat()}
|
||||
try:
|
||||
if signal.startswith('offsite.'):
|
||||
signals[signal] = archive_signal(entry, pinned_receipt(entry, root), now, root)
|
||||
continue
|
||||
path = (root / entry['path']).resolve()
|
||||
allowed = [root / 'docs/evidence']
|
||||
if signal == 'openbao.snapshot':
|
||||
|
|
@ -61,7 +141,7 @@ def recovery_signals(now, root=ROOT):
|
|||
if not timestamp(receipt['started_at']) <= completed <= now:
|
||||
raise ValueError('invalid receipt chronology')
|
||||
sample = {'result': 'pass', 'observed_at': receipt['finished_at']}
|
||||
except (OSError, ValueError, KeyError, TypeError):
|
||||
except (OSError, ValueError, KeyError, TypeError, AttributeError):
|
||||
pass
|
||||
signals[signal] = sample
|
||||
return signals
|
||||
|
|
|
|||
|
|
@ -77,10 +77,12 @@ def main():
|
|||
receipt['stage']='source_validation';checkpoint()
|
||||
source=json.loads(a.source_receipt.read_text())
|
||||
if (source.get('status')!='offsite_fetched_pending_isolated_restore'
|
||||
or source.get('archive_profile', 'full') not in ('full', 'essentials')
|
||||
or not a.source.name.endswith('.zip.age') or a.output.exists()
|
||||
or not 0<a.source.stat().st_size<=20*1024**3
|
||||
or source.get('ciphertext_sha256')!=digest(a.source)):
|
||||
raise ValueError('verified_source_required')
|
||||
receipt['archive_profile'] = source.get('archive_profile', 'full')
|
||||
receipt['stage']='cluster_identity';checkpoint()
|
||||
k=['kubectl','--kubeconfig',a.kubeconfig];assert_cluster(k)
|
||||
# Existing governed databases delivery, captured only in process memory.
|
||||
|
|
|
|||
|
|
@ -67,6 +67,27 @@ def test_primary_validation_failure_has_terminal_time_without_credentials(tmp_pa
|
|||
times(json.loads(output.read_text()))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('profile', ['full', 'essentials', 'unsupported'])
|
||||
def test_primary_preserves_profile_before_credential_access(tmp_path, profile):
|
||||
encrypted = tmp_path/'source.zip.age'; encrypted.write_bytes(b'fixture')
|
||||
source = tmp_path/'source.json'; output = tmp_path/'receipt.json'
|
||||
source.write_text(json.dumps(dict(status='offsite_fetched_pending_isolated_restore',
|
||||
archive_profile=profile, ciphertext_sha256=hashlib.sha256(b'fixture').hexdigest())))
|
||||
with patch.object(sys, 'argv', ['primary', '--source', str(encrypted),
|
||||
'--source-receipt', str(source), '--output', str(tmp_path/'download'),
|
||||
'--receipt', str(output), '--kubeconfig', 'unused']), \
|
||||
patch.object(primary, 'assert_cluster', side_effect=RuntimeError('stop before credentials')) as cluster:
|
||||
assert primary.main() == 1
|
||||
receipt = json.loads(output.read_text())
|
||||
if profile == 'unsupported':
|
||||
cluster.assert_not_called()
|
||||
assert 'archive_profile' not in receipt
|
||||
else:
|
||||
cluster.assert_called_once()
|
||||
assert receipt['archive_profile'] == profile
|
||||
times(receipt)
|
||||
|
||||
|
||||
def test_decryption_keeps_own_schema_and_times(tmp_path):
|
||||
encrypted=tmp_path/'encrypted';encrypted.write_bytes(b'fixture')
|
||||
source=tmp_path/'source.json';source.write_text(json.dumps(dict(schema='platform.forgejo-primary-archive.v1',status='primary_fetched_pending_application_restore',download_hash_matches=True,ciphertext_sha256=hashlib.sha256(b'fixture').hexdigest(),started_at='2000-01-01T00:00:00Z',finished_at='2000-01-01T00:00:01Z')))
|
||||
|
|
|
|||
130
tests/test_archive_recovery_evidence.py
Normal file
130
tests/test_archive_recovery_evidence.py
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
"""Full primary recovery requires a complete, ordered, hash-bound receipt chain."""
|
||||
import copy
|
||||
from datetime import datetime, timezone, timedelta
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'scripts'))
|
||||
from recovery_evidence import recovery_signals, ROOT
|
||||
from service_assurance import evaluate
|
||||
|
||||
NOW = datetime(2026, 9, 27, 12, tzinfo=timezone.utc)
|
||||
DESTINATION = 's3://railiance-platform-pg-backup/platform-pg/application-archives/forgejo/fixture.zip.age'
|
||||
|
||||
|
||||
def chain():
|
||||
transfer = dict(schema='platform.forgejo-primary-archive.v1',
|
||||
status='primary_fetched_pending_application_restore', stage='transfer_verified',
|
||||
started_at='2026-09-27T10:00:00Z', finished_at='2026-09-27T10:01:00Z',
|
||||
archive_profile='full', destination=DESTINATION, ciphertext_sha256='a'*64,
|
||||
ciphertext_bytes=123, uploaded_bytes=123, downloaded_bytes=123,
|
||||
multipart_completed=True, version_pinned=True, download_hash_matches=True)
|
||||
decryption = dict(schema='platform.forgejo-primary-decryption.v1',
|
||||
status='primary_fetched_pending_application_restore',
|
||||
started_at='2026-09-27T10:02:00Z', finished_at='2026-09-27T10:03:00Z',
|
||||
archive_profile='full', destination=DESTINATION, ciphertext_sha256='a'*64,
|
||||
ciphertext_bytes=123, decrypted=True, download_hash_matches=True,
|
||||
plaintext_sha256='b'*64)
|
||||
restore = dict(schema='platform.forgejo-isolated-restore.v1', status='restored',
|
||||
started_at='2026-09-27T10:04:00Z', finished_at='2026-09-27T10:05:00Z',
|
||||
archive_profile='full', source_provider='Scaleway', stage='package_blob_recovery',
|
||||
offsite_artifact=DESTINATION, ciphertext_sha256='a'*64, database_import=True,
|
||||
application_health=True, cleanup=True, repositories_verified=['fixture/repo'],
|
||||
package_blobs_verified=3, database_counts={'package_blobs': 3})
|
||||
return transfer, decryption, restore
|
||||
|
||||
|
||||
def write_chain(root, receipts, broken_link=None):
|
||||
def write(name, receipt):
|
||||
relative = f'docs/evidence/{name}.json'
|
||||
path = root / relative
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(receipt))
|
||||
return {'path': relative, 'sha256': hashlib.sha256(path.read_bytes()).hexdigest()}
|
||||
transfer, decryption, restore = copy.deepcopy(receipts)
|
||||
source = write('transfer', transfer)
|
||||
decryption['transfer_receipt_sha256'] = source['sha256'] if broken_link != 'transfer' else '0'*64
|
||||
decrypted = write('decryption', decryption)
|
||||
restore['transfer_receipt_sha256'] = decrypted['sha256'] if broken_link != 'decryption' else '0'*64
|
||||
recovered = write('restore', restore)
|
||||
index = {'schema': 'railiance-platform.recovery-evidence.v1', 'receipts': [
|
||||
{'signal': 'offsite.upload', **source},
|
||||
{'signal': 'offsite.restore', **recovered, 'decryption': decrypted, 'transfer': source}]}
|
||||
(root / 'assurance').mkdir(exist_ok=True)
|
||||
(root / 'assurance/recovery-evidence.json').write_text(json.dumps(index))
|
||||
return index
|
||||
|
||||
|
||||
def test_complete_chain_preserves_times_and_expires(tmp_path):
|
||||
write_chain(tmp_path, chain())
|
||||
signals = recovery_signals(NOW, tmp_path)
|
||||
assert signals['offsite.upload'] == {'result': 'pass', 'observed_at': '2026-09-27T10:01:00Z'}
|
||||
assert signals['offsite.restore'] == {'result': 'pass', 'observed_at': '2026-09-27T10:05:00Z'}
|
||||
later = NOW + timedelta(days=31)
|
||||
contract = {'cluster_uid': 'fixture', 'capture_max_age_seconds': 900,
|
||||
'signals': {s: {'owner': 'platform', 'max_age_seconds': 2592000} for s in signals}}
|
||||
report = evaluate(contract, {'schema': 'railiance-platform.observation.v1',
|
||||
'cluster_uid': 'fixture', 'captured_at': later.isoformat(),
|
||||
'signals': recovery_signals(later, tmp_path)}, later)
|
||||
assert all(s['state'] == 'stale' for s in report['signals'].values())
|
||||
|
||||
|
||||
@pytest.mark.parametrize('index,key,value', [
|
||||
(0, 'version_pinned', False), (0, 'download_hash_matches', False),
|
||||
(0, 'downloaded_bytes', 122), (0, 'ciphertext_bytes', True),
|
||||
(0, 'destination', 's3://other/fixture'), (0, 'archive_profile', 'essentials'),
|
||||
(0, 'finished_at', '2027-01-01T00:00:00Z'),
|
||||
(1, 'archive_profile', 'essentials'), (1, 'decrypted', False),
|
||||
(1, 'destination', DESTINATION + 'other'), (1, 'ciphertext_sha256', 'c'*64),
|
||||
(1, 'started_at', '2026-09-27T10:00:30Z'),
|
||||
(1, 'schema', 'platform.forgejo-primary-archive.v1'),
|
||||
(2, 'status', 'failed'), (2, 'cleanup', False), (2, 'application_health', False),
|
||||
(2, 'database_import', False), (2, 'archive_profile', 'essentials'),
|
||||
(2, 'source_provider', 'Nextcloud'), (2, 'offsite_artifact', DESTINATION + 'other'),
|
||||
(2, 'package_blobs_verified', 2), (2, 'package_blobs_verified', True),
|
||||
(2, 'repositories_verified', []), (2, 'finished_at', '2026-09-27T10:05:00'),
|
||||
(2, 'started_at', '2026-09-27T10:02:30Z'),
|
||||
])
|
||||
def test_incomplete_or_wrong_recovery_never_passes(tmp_path, index, key, value):
|
||||
receipts = chain()
|
||||
receipts[index][key] = value
|
||||
write_chain(tmp_path, receipts)
|
||||
signals = recovery_signals(NOW, tmp_path)
|
||||
assert signals['offsite.restore']['result'] == 'unavailable'
|
||||
if index == 0:
|
||||
assert signals['offsite.upload']['result'] == 'unavailable'
|
||||
|
||||
|
||||
@pytest.mark.parametrize('link', ['transfer', 'decryption'])
|
||||
def test_provenance_links_must_match_exact_bytes(tmp_path, link):
|
||||
write_chain(tmp_path, chain(), broken_link=link)
|
||||
assert recovery_signals(NOW, tmp_path)['offsite.restore']['result'] == 'unavailable'
|
||||
|
||||
|
||||
@pytest.mark.parametrize('case', ['drift', 'missing', 'escape', 'missing_time', 'malformed'])
|
||||
def test_untrusted_files_are_unavailable(tmp_path, case):
|
||||
index = write_chain(tmp_path, chain())
|
||||
entry = index['receipts'][1]
|
||||
path = tmp_path / entry['path']
|
||||
if case == 'drift': path.write_text('{}')
|
||||
if case == 'missing': path.unlink()
|
||||
if case == 'escape': entry['path'] = '/tmp/outside-recovery-evidence.json'
|
||||
if case in ('missing_time', 'malformed'):
|
||||
receipt = json.loads(path.read_text())
|
||||
if case == 'missing_time': del receipt['finished_at']
|
||||
else: receipt = []
|
||||
path.write_text(json.dumps(receipt))
|
||||
entry['sha256'] = hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
(tmp_path / 'assurance/recovery-evidence.json').write_text(json.dumps(index))
|
||||
assert recovery_signals(NOW, tmp_path)['offsite.restore']['result'] == 'unavailable'
|
||||
|
||||
|
||||
def test_historical_undated_receipt_is_not_freshened(tmp_path):
|
||||
receipts = list(chain())
|
||||
receipts[2] = json.loads((ROOT / 'docs/evidence/RPF-WP-0038-primary-archive-restore-2026-09-06.json').read_text())
|
||||
write_chain(tmp_path, receipts)
|
||||
assert recovery_signals(NOW, tmp_path)['offsite.restore']['result'] == 'unavailable'
|
||||
|
|
@ -1,37 +1,25 @@
|
|||
# Current platform work
|
||||
|
||||
Reviewed 2026-09-15. Open workplans below; RPF-WP-0029 finished on predecessor
|
||||
unshare. Completed designs and implementations are under `archived/`; their IDs
|
||||
and UUIDs are preserved. The number of blocked plans is not a count of missing
|
||||
implementations or independent incidents.
|
||||
Reviewed September 27, 2026. Eight workplans remain blocked with 23 waiting
|
||||
tasks. No active, ready or proposed source workplan remains. Completed work
|
||||
retains its IDs and managed UUIDs, including plans under `archived/`.
|
||||
|
||||
| Workplan | Purpose and next gate | S3 boundary |
|
||||
| Workplan | Remaining tasks | Next dependency |
|
||||
| --- | --- | --- |
|
||||
| [RPF-WP-0027](RPF-WP-0027-keycape-live-secret-exposure-recovery.md) | Incident custody and final evidence; accept NetKingdom's residual disposition and publish exact custody handoff | The bundle was already rotated. Provider/MFA reconciliation belongs to NetKingdom. |
|
||||
| [RPF-WP-0015](RPF-WP-0015-audit-core-custody-and-recovery-coordination.md) | T02/T03 | Fresh recovery windows, synthetic sender/abort owner and snapshot/quorum/access evidence |
|
||||
| [RPF-WP-0027](RPF-WP-0027-keycape-live-secret-exposure-recovery.md) | T03/T06 | Complete historical resolver custody/routing contract; T05 closed from September 23 operator disposition and owner receipt |
|
||||
| [RPF-WP-0035](RPF-WP-0035-credential-lane-implementation.md) | T02/T03/T06/T07/T08 | Exact service registration/custody, human memo acceptance, reader/disablement returns, governed npm migration and formerly-valid audit-bearer revocation proof |
|
||||
| [RPF-WP-0036](RPF-WP-0036-platform-service-assurance.md) | T03/T04/T06 | Current recovery/cadence/custody evidence, Q2 production delivery and owner/projection acceptance; local archive adapter implemented |
|
||||
| [RPF-WP-0038](RPF-WP-0038-forgejo-scaleway-primary-coverage.md) | T04 | Durable scheduled caller, canonical verified inventory and quota/retention gates; September 15 cutover/expiration hold persists |
|
||||
| [RPF-WP-0043](RPF-WP-0043-policy-nexus-argocd-onboarding.md) | T02/T03/T04 | Cross-owner chart/values agreement, committed values and source access, zero-diff proof and adoption |
|
||||
| [RPF-WP-0044](RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md) | T03–T08 | Per-app promotion gates, issue-core credentials/ownership, target-revenue hook acceptance, ESO adoption/observation and readable old-controller inventory |
|
||||
| [RPF-WP-0048](RPF-WP-0048-activity-core-gitops-adoption.md) | T02 | Healthy observation through September 28 at 16:06:22 Berlin plus bounded authenticated release broker/admission and rollback proof |
|
||||
|
||||
| [RPF-WP-0025](RPF-WP-0025-openbao-operator-only-access.md) | Public Ingress retracted 2026-09-15; private tunnel remains | DNS withdrawal with railiance-infra; rollback phrase still available. |
|
||||
| [RPF-WP-0015](RPF-WP-0015-audit-core-custody-and-recovery-coordination.md) | Two prepared recovery exercises; registered load driver exists; fresh sender/window/abort approvals and custody readiness remain | S3 contributes lease/ESO and snapshot/unseal proof; S1/S2 and audit-core execute their parts. |
|
||||
| [RPF-WP-0035](RPF-WP-0035-credential-lane-implementation.md) | Three remaining lanes: secrets-engine JWT, Fluid operator KV, KeyCape approval clients | Signing T04 is complete; T05 admission answered and awaiting owner approval plus a founder-attended window. |
|
||||
| [RPF-WP-0036](RPF-WP-0036-platform-service-assurance.md) | Implemented local assurance/admission; waits for recurring restore evidence, Q2 reception and owner handoff | Run the assurance commands; live acceptance and external ownership remain gated. |
|
||||
| [RPF-WP-0038](RPF-WP-0038-forgejo-scaleway-primary-coverage.md) | Native backup, full Scaleway archive recovery and 273 MiB Nextcloud essentials recovery verified; scheduled tier cutover remains | Bind recurring caller/dependencies, verified inventory, quota checks and separate owner retention. |
|
||||
| [RPF-WP-0043](RPF-WP-0043-policy-nexus-argocd-onboarding.md) | Onboard production-approved rapp-policy-nexus to the ArgoCD lane by 2026-12-21; T01 confirms ArgoCD reconciles on railiance01 (unverified) | Plan only; adoption waits on the founder's go-ahead and rapp-policy-nexus's manifest decision. |
|
||||
Latest [review and evidence](../history/2026-09-27-loose-end-review.md).
|
||||
No new task or workplan was created. Existing completed credential reviews,
|
||||
delivery, retention projection and rotations are not reopened by these waits.
|
||||
|
||||
|
||||
RPF-WP-0036-T02/T05/T07 are complete; T03/T04/T06 retain the remaining
|
||||
acceptance gates. Treat credential exposure closure as the highest-priority attended
|
||||
work; task order does not combine or waive approvals.
|
||||
|
||||
[Assessment and disposition of every plan](../history/2026-09-05-platform-intent-workplan-assessment.md)
|
||||
and [generated current record index](../WORK-RECORDS.md).
|
||||
|
||||
Do not recreate completed workplans because an old Hub alias or generated brief
|
||||
still shows them active. Use source IDs, and follow AGENTS.md for verified sync.
|
||||
|
||||
## Latest closure review
|
||||
|
||||
[2026-09-05 blocker review](../history/2026-09-05-blocked-workplan-closure-review.md):
|
||||
At that review: 12 unfinished tasks across six genuine blocked plans.
|
||||
The September 6 follow-up adds WP-0038 with one remaining full-archive task. All terminal plans have
|
||||
only done/cancel tasks. Completed ESO recovery RPF-WP-0037 is archived.
|
||||
Three retired Hub aliases still appear open; they are a derived-view defect,
|
||||
not three more workplans. Use this file before the dated generated brief.
|
||||
Source files are authoritative. The generated brief still contains retired
|
||||
aliases and stale statuses; do not recreate work from it. Routine synchronization
|
||||
uses the exact-commit Repo Manager receipt described in AGENTS.md. Legacy alias
|
||||
repair remains the scoped owner dependency in WP-0036-T06.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ flavor: implementation
|
|||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-22"
|
||||
updated: "2026-09-05"
|
||||
updated: "2026-09-27"
|
||||
related:
|
||||
- AUDIT-WP-0008
|
||||
- WH-ENG-20260822-AUDIT-E2-01
|
||||
|
|
@ -348,3 +348,7 @@ is no longer missing. T02 waits on its separately approved sender identity,
|
|||
fresh bounded window, abort operator and live recovery receipt. Local driver
|
||||
success does not prove lease revocation/ESO recovery. T03 remains a separate
|
||||
outage exercise; no historical window or terminal NO-GO may be reused.
|
||||
|
||||
## Loose-end review — 2026-09-27
|
||||
|
||||
T02/T03 remain waiting on fresh attended execution windows, named abort operators, current custody/quorum evidence and owner execution. The implemented load driver and prior procedure approvals do not supply a fresh live recovery receipt. No expired window was reused.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ flavor: implementation
|
|||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-23"
|
||||
updated: "2026-09-15"
|
||||
updated: "2026-09-27"
|
||||
related:
|
||||
- KEY-WP-0011
|
||||
origin: routed
|
||||
|
|
@ -110,7 +110,7 @@ and all T03 acknowledgements. No value may enter captured output.
|
|||
|
||||
```task
|
||||
id: RPF-WP-0027-T05
|
||||
status: wait
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "9cb5fa67-012a-58cf-bafb-e7c7d4f9782d"
|
||||
```
|
||||
|
|
@ -172,3 +172,7 @@ and acceptable disposition. Overall incident closure remains open.
|
|||
No new owner acceptance or coordination message is asserted by this review.
|
||||
Keep this incident separate from the new-lane queue; broad lane approval cannot
|
||||
close an exposure.
|
||||
|
||||
## Loose-end review — 2026-09-27
|
||||
|
||||
T05 is now done by the newer owner record: NK-WP-0033 accepted the operator ruling on 2026-09-23 and recorded the green attended read-only resolver/MFA/health/cleanup receipt. Predecessor denial remains explicitly NOT-PROVEN, with the unavailable-predecessor disposition accepted by Bernd Worsch; it is not relabelled as a successful negative test. KEY-WP-0011 already closes the other credential-class rotation/recovery evidence. See `docs/evidence/2026-09-27-keycape-incident-owner-return.json`. T03/T06 still wait for the complete platform custody/routing handoff. The owner names operators/lldap/admin and operators/privacyidea/pi-admin, but does not supply the complete field/auth/expiry/handoff contract required by T06. The September 15 instruction to leave historical routing lanes blocked remains in force. No repeat rotation or predecessor recovery was attempted.
|
||||
|
|
|
|||
|
|
@ -415,7 +415,7 @@ into this client-identity grant.
|
|||
|
||||
```task
|
||||
id: RPF-WP-0035-T08
|
||||
status: progress
|
||||
status: wait
|
||||
priority: high
|
||||
assignee: railiance-platform
|
||||
needs_human: false
|
||||
|
|
@ -696,3 +696,7 @@ T07 consumed the confirmed legacy consumer return. The stale value-comparison
|
|||
ask is removed. WARDEN-WP-0037-T03's no-rotation hold stays in force until the
|
||||
governed native migration is evidenced. Legacy destruction follows migration;
|
||||
neither source reconciliation nor the historical pilot is that evidence.
|
||||
|
||||
## Loose-end review — 2026-09-27
|
||||
|
||||
T08 now explicitly waits for formerly-valid audit-bearer revocation acceptance from AUDIT-WP-0009-T09/T11. Native delivery, producer checks and independent readback already passed; do not reopen login, seed or review gates. T02/T03/T06/T07 retain their latest exact service registration, signed-in human acceptance, owner delivery/disposition and governed-consumer migration dependencies. No credential value was read or changed.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ status: blocked
|
|||
flavor: implementation
|
||||
owner: codex
|
||||
created: "2026-09-05"
|
||||
updated: "2026-09-06"
|
||||
updated: "2026-09-27"
|
||||
state_hub_workstream_id: "ca639c3d-3a87-5fa4-ad13-6f2e014b0c84"
|
||||
---
|
||||
|
||||
|
|
@ -314,3 +314,7 @@ RTEL-WP-0002-T04: accepted package/runtime, authenticated execution, actual
|
|||
operator recipient, cadence/storage/retention and independent receiver watchdog,
|
||||
then acknowledged controlled delivery. Local test-inbox visibility is not that
|
||||
live receipt; S3 remains unmonitored until acceptance.
|
||||
|
||||
## Loose-end review — 2026-09-27
|
||||
|
||||
Completed the local full-primary archive assurance adapter under T03. It validates ordered transfer/decryption/restore receipts, exact provenance hashes, full profile, version-pinned verified download and application/database/repository/package/cleanup proof; historical undated receipts remain ineligible. Updated producer profile propagation and assurance documentation. Fresh live metadata reports 18 healthy signals, five missing recovery/upload signals and one stale OpenBao snapshot; transport remains unmonitored. T03/T04/T06 remain waiting on current recovery/cadence/custody proof, Q2 production delivery acceptance and owner/derived-record acceptance respectively. RTEL-WP-0002-T04 already selects rapp-telemetry; the stale claim that no receiver implementation/package exists is superseded. See `history/2026-09-27-loose-end-review.md`.
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ type: workplan
|
|||
title: "Close Forgejo primary backup coverage on Scaleway"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: active
|
||||
status: blocked
|
||||
flavor: implementation
|
||||
owner: codex
|
||||
created: "2026-09-06"
|
||||
updated: "2026-09-15"
|
||||
updated: "2026-09-27"
|
||||
state_hub_workstream_id: "7beec1a7-aa82-5a36-9a66-6b60008a2455"
|
||||
---
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ removed. Evidence: `docs/evidence/forgejo-scaleway-restore-2026-09-06.json`.
|
|||
|
||||
```task
|
||||
id: RPF-WP-0038-T04
|
||||
status: progress
|
||||
status: wait
|
||||
priority: high
|
||||
state_hub_task_id: "a4807df0-ec96-58f1-9cbd-42b1dcde0d6f"
|
||||
```
|
||||
|
|
@ -118,3 +118,7 @@ the existing durable caller, inventory, quota and retention gates.
|
|||
**Operator decision, 2026-09-15:** do not expire retained backups or cut over
|
||||
scheduled secondary delivery. The planner and attended executor stay idle until
|
||||
durable caller/inventory/quota gates are closed.
|
||||
|
||||
## Loose-end review — 2026-09-27
|
||||
|
||||
T04 now explicitly waits. Primary and essentials manual recovery are already proven. Durable scheduled caller/dependency binding, canonical verified inventory, quota/retention gates and owner activation are still absent. September 15 prohibits expiration and scheduled secondary cutover until those gates close; no retained backups or schedules were changed. New primary transfer receipts preserve archive_profile for the assurance adapter in WP-0036-T03.
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ type: workplan
|
|||
title: "Onboard rapp-policy-nexus to the ArgoCD production lane"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: active
|
||||
status: blocked
|
||||
flavor: planning
|
||||
owner: railiance-platform
|
||||
topic_slug: railiance
|
||||
created: "2026-09-21"
|
||||
updated: "2026-09-22"
|
||||
updated: "2026-09-27"
|
||||
due: "2026-12-21"
|
||||
related: [RPF-WP-0022]
|
||||
state_hub_workstream_id: "ec41a4bd-df18-5b07-9b63-ccb80d9f001c"
|
||||
|
|
@ -231,3 +231,7 @@ the inventory.
|
|||
- **T05 done.** Gap declared and inventoried in
|
||||
`docs/direct-apply-gap-inventory.md`, with a per-group proposal for the
|
||||
founder. No target changed.
|
||||
|
||||
## Loose-end review — 2026-09-27
|
||||
|
||||
The workplan is blocked on the source-owner agreement and its downstream adoption gates. RAPP-POLICY-NEXUS-WP-0002 proposes a multi-source Application: chart in rapp-policy-nexus and release values in railiance-apps. This supersedes the earlier platform-only suggestion to put production values in the package repository. The platform accepts that shape and the helm/policy-nexus path exception in principle; it still needs railiance-apps acceptance, an actual committed values path/revision, source access and a zero-diff render before T02/T03 can close. No owner acceptance or cross-repository change is inferred. T01 remains proven by current railiance01 Synced/Healthy evidence.
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ type: workplan
|
|||
title: "ArgoCD phase B: adopt the four existing Applications on railiance01"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: active
|
||||
status: blocked
|
||||
flavor: planning
|
||||
owner: railiance-platform
|
||||
topic_slug: railiance
|
||||
created: "2026-09-21"
|
||||
updated: "2026-09-21"
|
||||
updated: "2026-09-27"
|
||||
related: [RPF-WP-0043, RPF-WP-0022]
|
||||
state_hub_workstream_id: "98140775-3b9a-5cf9-9af6-722502d487dc"
|
||||
---
|
||||
|
|
@ -185,7 +185,7 @@ Rollback:
|
|||
|
||||
```task
|
||||
id: RPF-WP-0044-T03
|
||||
status: progress
|
||||
status: wait
|
||||
priority: high
|
||||
state_hub_task_id: "6d5fc801-e361-579b-bcd8-6fe719a82e94"
|
||||
```
|
||||
|
|
@ -256,7 +256,7 @@ whitelist. Live check: `rapp-issue-core make verify-live`. Workload restore:
|
|||
|
||||
```task
|
||||
id: RPF-WP-0044-T05
|
||||
status: progress
|
||||
status: wait
|
||||
priority: medium
|
||||
state_hub_task_id: "d418068a-6fb0-5416-aac5-d23c93924d9c"
|
||||
```
|
||||
|
|
@ -317,7 +317,7 @@ railiance01 path is a live production change, and `RPF-WP-0043-T04`
|
|||
|
||||
```task
|
||||
id: RPF-WP-0044-T08
|
||||
status: todo
|
||||
status: wait
|
||||
priority: low
|
||||
state_hub_task_id: "55d1382f-5862-5321-a1c9-96767764ba43"
|
||||
```
|
||||
|
|
@ -326,3 +326,7 @@ Planning only. Needs a read-only check of coulombcore's ArgoCD, outside this
|
|||
session's scope. Under Option A, retiring it also removes `argocd/applications/`.
|
||||
Also hand back to the cluster layer: the phase A install is not declared in
|
||||
any repository and its pods have no resource requests (BestEffort).
|
||||
|
||||
## Loose-end review — 2026-09-27
|
||||
|
||||
T03/T05 passed their elapsed healthy observation gate: current ArgoCD status is Synced/Healthy with last healthy transitions on September 21; openbao is Valid and issue-core-runtime is SecretSynced. They now wait on the remaining automation go-aheads and, for target-revenue, hook-owner acceptance. T06 local preparation is complete: the inactive ESO draft protects all 20 CRDs from prune/delete. The pinned 0.16.1 chart renders 39 objects; server-side diff is exactly the 20 protective metadata annotations, with no spec changes. All 25 ClusterSecretStores are Valid. T04 still needs the repository credential/production-owner contract; T07 depends on the per-app gates. T08 has a concrete retirement procedure at `docs/argocd-coulombcore-retirement.md`, but its required live inventory is blocked: SSH works and Kubernetes rejects both default and explicit local k3s kubeconfigs. No controller or workload was changed. Evidence: `docs/evidence/2026-09-27-argocd-loose-end-status.json` and `docs/evidence/2026-09-27-eso-adoption-preparation.json`.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ type: workplan
|
|||
title: "Adopt activity-core application runtime into railiance01 GitOps"
|
||||
domain: financials
|
||||
repo: railiance-platform
|
||||
status: active
|
||||
status: blocked
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-09-27"
|
||||
|
|
@ -130,3 +130,7 @@ were made by this probe. See docs/evidence/2026-09-27-digest-retention-release.j
|
|||
New healthy observation start is 2026-09-27T14:06:22Z after worker rollout;
|
||||
earliest eligibility is September 28 at 16:06:22 Europe/Berlin. Automation remains
|
||||
off. T02 still owns the scoped broker/admission and observation requirements.
|
||||
|
||||
## Loose-end review — 2026-09-27
|
||||
|
||||
The workplan is blocked on T02. Current activity-core remains Synced/Healthy at a12f1169f9d130058ce767f5b26de0606997916c, with health transition 2026-09-27T14:06:22Z. Earliest observation eligibility remains September 28 at 16:06:22 Europe/Berlin. The authenticated bounded broker/admission and rollback proof remain owned jointly with ACTIVITY-WP-0041-T03. Elapsed time is not release-identity admission. T01/T03 remain done; no root automation, pruning or credential delegation was enabled.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue