Updated by fix-consistency on 2026-09-21: - workplan status: ready → active Assistant: claude-code Assistant-Model: opus Assistant-Process: 63291@bnt-lap001 Assistant-Session: 8bd77868-ca68-4f49-bb1e-d539ecc0d703
220 lines
9 KiB
Markdown
220 lines
9 KiB
Markdown
---
|
|
id: RPF-WP-0043
|
|
type: workplan
|
|
title: "Onboard rapp-policy-nexus to the ArgoCD production lane"
|
|
domain: financials
|
|
repo: railiance-platform
|
|
status: active
|
|
flavor: planning
|
|
owner: railiance-platform
|
|
topic_slug: railiance
|
|
created: "2026-09-21"
|
|
updated: "2026-09-21"
|
|
due: "2026-12-21"
|
|
related: [RPF-WP-0022]
|
|
state_hub_workstream_id: "ec41a4bd-df18-5b07-9b63-ccb80d9f001c"
|
|
---
|
|
|
|
The founder, Bernd Worsch, decided on 2026-09-21, exercising `GOVERN @ estate`,
|
|
that changes to `production-approved` workloads go through `CONSTRUCT @` the
|
|
manifest repository, reconciled by ArgoCD through `railiance-apps-root`. The
|
|
record is `the-custodian/docs/kubernetes-change-gate-decision.md`. Terms follow
|
|
SecurityCanon Mode of Authority v0.2.0, which is still a draft.
|
|
|
|
`rapp-policy-nexus` is `production-approved` (reef-railiance
|
|
`bindings/rapps.yaml`), but no ArgoCD Application manages it. Its changes
|
|
today are Helm releases, `make deploy` in rapp-policy-nexus: `helm upgrade
|
|
--install policy-nexus` on railiance01, namespace `policy-nexus`. Until
|
|
2026-12-21 those changes keep `activation=APPROVED` by founder plan approval,
|
|
and each one is recorded as production-tier. This plan onboards policy-nexus by
|
|
2026-12-21.
|
|
|
|
**This plan only prepares the change. It does not perform it.** Adding
|
|
`argocd/applications/policy-nexus.application.yaml` is a live production change.
|
|
Once it is on `main`, `railiance-apps-root` syncs it with prune and self-heal,
|
|
and ArgoCD takes ownership of running resources. Nothing in this plan is
|
|
applied, pushed as an Application, or synced without the founder's go-ahead
|
|
(T04).
|
|
|
|
Out of scope: the legacy whynot-design npm location (RPF-WP-0035-T07). It
|
|
stays untouched and unwrapped while this lane moves.
|
|
|
|
## Confirm ArgoCD actually reconciles on railiance01
|
|
|
|
```task
|
|
id: RPF-WP-0043-T01
|
|
status: todo
|
|
priority: high
|
|
state_hub_task_id: "d6a7a480-6251-504a-aa5f-ab9c04fe1e79"
|
|
```
|
|
|
|
This repository cannot confirm it; see `docs/argocd-gitops.md` § Production
|
|
Change Path. The only record of ArgoCD's health is from 2026-06 and predates
|
|
the correction of the railiance01/coulombcore naming. Later records call the
|
|
controller "coulombcore ArgoCD", and all Applications target
|
|
`kubernetes.default.svc`.
|
|
|
|
Attended, read-only, against a kubeconfig whose server is verified to be
|
|
92.205.62.239:
|
|
|
|
1. `kubectl get nodes -o wide`: confirm the node IP.
|
|
2. `kubectl -n argocd get deploy,sts` and `make argocd-status`.
|
|
3. `kubectl -n argocd get application railiance-apps-root -o jsonpath='{.status.sync.status} {.status.health.status} {.status.sync.revision}'`.
|
|
Compare the revision with Forgejo `main`.
|
|
|
|
Record the output as `docs/evidence/<date>-argocd-railiance01-status.json`.
|
|
If ArgoCD is absent or not syncing on railiance01, stop this plan. Report to the
|
|
founder and the-custodian that the production row has no working path. An
|
|
ArgoCD install belongs to the cluster layer and needs its own go-ahead.
|
|
|
|
## Agree where policy-nexus's manifests live
|
|
|
|
```task
|
|
id: RPF-WP-0043-T02
|
|
status: wait
|
|
priority: high
|
|
state_hub_task_id: "49143c5e-a455-526e-a26f-403dc2fb075a"
|
|
```
|
|
|
|
Per the tenant contract, workload manifests stay in the tenant repository.
|
|
`rapp-policy-nexus` owns that repository
|
|
(`forgejo.coulomb.social/coulomb/rapp-policy-nexus`) and decides this itself.
|
|
We coordinate through the hub and do not decide it here.
|
|
|
|
Proposal to put to rapp-policy-nexus:
|
|
|
|
- The source is the existing chart `helm/policy-nexus`.
|
|
- A committed values file, for example `k8s/railiance/values-railiance01.yaml`,
|
|
pins `image.digest`, `publicationManifestDigest`, `sourceInventoryDigest` and
|
|
`sourceSetDigest`. Today they are passed as `--set-string` at deploy time.
|
|
After adoption, a release is a commit that changes these pins.
|
|
- `helm.releaseName: policy-nexus`, so that rendered names and the
|
|
`app.kubernetes.io/instance` label match the live release.
|
|
- Once adopted, `make deploy` / `helm upgrade` stops being a production path.
|
|
It would fight self-heal. Whether to keep it for pre-production is for
|
|
rapp-policy-nexus to decide.
|
|
|
|
Platform checks:
|
|
|
|
- The chart renders Deployment, Service, ServiceAccount, Ingress and
|
|
NetworkPolicy. All five are in the `railiance-tenants` whitelist.
|
|
- Repository access: if the repository is private, it needs an ArgoCD
|
|
repository credential at `platform/operators/argocd/repositories/rapp-policy-nexus`.
|
|
That credential goes through its own CCR. No value is handled in this plan.
|
|
|
|
**Unblock:** rapp-policy-nexus replies with the path, the values file, and
|
|
whether the repository is public.
|
|
|
|
## Prepare the Application and the dry-run evidence
|
|
|
|
```task
|
|
id: RPF-WP-0043-T03
|
|
status: wait
|
|
priority: high
|
|
state_hub_task_id: "2afb1aac-66dd-5e1e-92e1-fc020a59a927"
|
|
```
|
|
|
|
Draft the Application in this workplan or in a review branch, **not** under
|
|
`argocd/applications/` on `main`. Draft shape for adoption:
|
|
|
|
```yaml
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: policy-nexus # no finalizers: deletion must not cascade
|
|
namespace: argocd
|
|
labels:
|
|
app.kubernetes.io/part-of: railiance-gitops
|
|
spec:
|
|
project: railiance-tenants
|
|
source:
|
|
repoURL: https://forgejo.coulomb.social/coulomb/rapp-policy-nexus.git
|
|
targetRevision: <pinned commit>
|
|
path: helm/policy-nexus
|
|
helm:
|
|
releaseName: policy-nexus
|
|
valueFiles: [<agreed values file>]
|
|
destination:
|
|
server: https://kubernetes.default.svc
|
|
namespace: policy-nexus
|
|
syncPolicy: # adoption stage: no `automated` block
|
|
syncOptions:
|
|
- CreateNamespace=false
|
|
- ApplyOutOfSyncOnly=true
|
|
- PruneLast=true
|
|
```
|
|
|
|
Read-only evidence to collect before T04, in an attended session:
|
|
|
|
1. `helm -n policy-nexus get values policy-nexus` and `helm history`: the live
|
|
digests and the current revision number, which is the rollback target. Do
|
|
not print anything else from the release.
|
|
2. Render the chart with the agreed values file. Run `kubectl diff
|
|
--server-side` of the render against the live namespace. Expected result:
|
|
no spec change, and only label or annotation differences.
|
|
3. List every object in `policy-nexus`. Mark which ones the render does not
|
|
contain, for example Helm release Secrets `sh.helm.release.v1.*`. Only
|
|
resources carrying ArgoCD's tracking label are pruned. Confirm that none of
|
|
the unrendered objects carry it.
|
|
|
|
Stop conditions: any Deployment spec or image change, any object that the
|
|
render lacks but that carries the tracking label, or a digest mismatch.
|
|
|
|
## Adopt policy-nexus (live, founder go-ahead)
|
|
|
|
```task
|
|
id: RPF-WP-0043-T04
|
|
status: wait
|
|
priority: high
|
|
state_hub_task_id: "8638fa73-439d-5dcd-85c7-81aa125170e1"
|
|
```
|
|
|
|
**Waits on the founder's go-ahead.** This is a `CONSTRUCT @ railiance-platform`
|
|
change with `activation=APPROVED`. The merge is the gate, and it is a live
|
|
production change. Do not take it on the basis of this plan alone.
|
|
|
|
1. Merge the Application exactly as in T03, with no `automated` sync.
|
|
`railiance-apps-root` creates the Application object. It does not touch
|
|
policy-nexus resources, because the child has no automated sync.
|
|
2. `argocd app diff policy-nexus`, or read the UI diff. It must match T03
|
|
step 2. Any other result means stop, then roll back (step R1).
|
|
3. `argocd app sync policy-nexus` with pruning left off, which is the default
|
|
for a manual sync. Then run rapp-policy-nexus `make verify-live` with the
|
|
pinned digests.
|
|
4. After the workload has been Synced and Healthy for at least 24 hours, a
|
|
second merge adds `automated: {prune: true, selfHeal: true}`, matching the
|
|
tenant contract. This needs a second go-ahead.
|
|
5. Record evidence as `docs/evidence/<date>-policy-nexus-argocd-adoption.json`.
|
|
Notify rapp-policy-nexus and ops-mason that policy-nexus is now in the
|
|
production row. Its transition exception ends.
|
|
|
|
Rollback:
|
|
|
|
- **R1, before step 4:** revert the merge commit. The root app prunes the
|
|
child Application object. The child has no finalizer, so the deletion does
|
|
not cascade and the workload keeps running unchanged.
|
|
- **R2, after step 4:** revert the automated-sync commit first, then R1.
|
|
Do not patch the child Application by hand, because the root app's
|
|
self-heal restores it from git. A hand patch is a direct `ADMINISTER` under
|
|
`BREAK_GLASS`. It is recorded and reconciled back into git.
|
|
- **Workload restore:** only after ArgoCD no longer manages policy-nexus, run
|
|
rapp-policy-nexus `make rollback REVISION=<revision from T03>`. Otherwise
|
|
self-heal fights the rollback.
|
|
|
|
## Declare the platform's own direct-apply gap
|
|
|
|
```task
|
|
id: RPF-WP-0043-T05
|
|
status: todo
|
|
priority: medium
|
|
state_hub_task_id: "91431560-79d4-5352-a6b5-f12850315dd2"
|
|
```
|
|
|
|
Under the decision, platform objects without a readiness state default to
|
|
the production tier. This repository still changes several of them through
|
|
direct Make targets. Examples are the railiance01 ClusterSecretStores,
|
|
OpenBao configuration and the ArgoCD bootstrap. That is `target-audited`
|
|
evidence only. Inventory those targets, declare the gap as not conforming,
|
|
and propose to the founder which ones move to a reconciled lane and which
|
|
stay direct under `APPROVED`. Do not change a target's behaviour as part of
|
|
the inventory.
|