Complete ISSUE-WP-0007 railiance01 cutover
This commit is contained in:
parent
3523a7decc
commit
51440da148
8 changed files with 35 additions and 344 deletions
13
SCOPE.md
13
SCOPE.md
|
|
@ -112,8 +112,8 @@ also `sync_metadata.mapping` and a row in `mappings.db`.
|
|||
| Artifact | Provides |
|
||||
| --- | --- |
|
||||
| PyPI package | Built wheel/sdist; Makefile targets publish to Coulomb Gitea/Forgejo registry |
|
||||
| Docker + `k8s/railiance/` | GitOps-style deploy on railiance01 (deployment, service, configmap, ExternalSecret) |
|
||||
| `docs/argocd-gitops.md` | Operator runbook for that deploy |
|
||||
| Docker image | Built and published by this app repo; production consumes an immutable digest |
|
||||
| `rapp-issue-core` | Authoritative railiance01 runtime package: manifests, private Service, ExternalSecret references, NetworkPolicy, rollout, rollback, and live evidence |
|
||||
| `docs/package-release.md` | Release notes for packaging |
|
||||
| `registry/` + `CAPABILITY-issue-tracking.yaml` | Reuse-surface / capability federation metadata |
|
||||
| Tests | `tests/` unit coverage for models, CLI, backends, API ingest/query, mapping |
|
||||
|
|
@ -313,11 +313,14 @@ issue_core/
|
|||
cli/ # Click: issue, project, map, backend, sync, serve
|
||||
api/ # FastAPI: ingest + query (+ auth, schemas)
|
||||
tests/
|
||||
docs/ # gitops, nats stub, mapping design, boundary-sync policy
|
||||
k8s/railiance/ # deploy manifests
|
||||
docs/ # nats stub, mapping design, boundary-sync policy
|
||||
workplans/ # ADR-001 work items for this repo
|
||||
```
|
||||
|
||||
Production runtime packaging is intentionally outside this tree in the sibling
|
||||
`rapp-issue-core` repository. This repo remains authoritative for domain code,
|
||||
tests, image construction, and Forgejo image publication.
|
||||
|
||||
| Concern | Choice |
|
||||
| --- | --- |
|
||||
| Language | Python 3.8+ |
|
||||
|
|
@ -339,7 +342,7 @@ workplans/ # ADR-001 work items for this repo
|
|||
- `docs/boundary-sync-and-status-mapping.md` — dual-lifecycle outward policy (v1)
|
||||
- `docs/intent-work-record-alignment-review.md` — INTENT vs work-record audit
|
||||
- `docs/nats-task-ingestion.md` — NATS design stub
|
||||
- `docs/argocd-gitops.md` — railiance01 deploy
|
||||
- `rapp-issue-core` — authoritative railiance01 deployment and live evidence
|
||||
- `AGENT_INTEGRATION.md` — library patterns for tracker ops
|
||||
- `workplans/ISSUE-WP-0004-align-with-work-record-canon.md` — initial framing pivot
|
||||
- `workplans/ISSUE-WP-0005-connector-alignment-implementation.md` — **finished**: mapping + scope gaps
|
||||
|
|
|
|||
|
|
@ -1,168 +0,0 @@
|
|||
# ArgoCD GitOps deployment - railiance01
|
||||
|
||||
This runbook captures the issue-core side of the railiance01 GitOps pilot.
|
||||
It keeps secrets out of Git and leaves platform-owned bootstrap steps in
|
||||
railiance-platform.
|
||||
|
||||
## Source layout
|
||||
|
||||
- Workload bundle: `issue-core/k8s/railiance/`
|
||||
- Image: `forgejo.coulomb.social/coulomb/issue-core:0.2.1`
|
||||
- Container port and Service port: `8765`
|
||||
- Cluster Service URL: `http://issue-core.issue-core.svc.cluster.local:8765`
|
||||
- Tenant Application: `railiance-platform/argocd/applications/issue-core.application.yaml`
|
||||
|
||||
The `Application` should point at this repo's `k8s/railiance` path and use
|
||||
`CreateNamespace=true` for the `issue-core` namespace. The namespace itself is
|
||||
therefore intentionally not duplicated in this bundle.
|
||||
|
||||
## Platform gates
|
||||
|
||||
The following pieces are owned by railiance-platform for the live pilot and for
|
||||
any future cluster replay:
|
||||
|
||||
- ArgoCD repository credentials and the project/app-of-apps convention.
|
||||
- The `issue-core` ArgoCD `Application`.
|
||||
- External Secrets Operator and a `ClusterSecretStore` named `openbao`.
|
||||
- OpenBao entries for the issue-core runtime Secret.
|
||||
|
||||
For the 2026-06-25 live deployment, these gates were satisfied and the
|
||||
`issue-core` Application reached Synced/Healthy with image `0.2.1`.
|
||||
|
||||
## Secret contract
|
||||
|
||||
Kubernetes Secret name: `issue-core-runtime`
|
||||
|
||||
Current issue-core manifest path:
|
||||
|
||||
```text
|
||||
platform/workloads/issue-core/issue-core/issue-core-runtime
|
||||
```
|
||||
|
||||
Credential custody is owned by railiance-platform/OpenBao. For agents, first
|
||||
use the non-secret route catalog entry `activity-core-issue-sink` to confirm
|
||||
the activity-core + issue-core pairing, and never request the value from
|
||||
ops-warden.
|
||||
|
||||
Required properties:
|
||||
|
||||
- `ISSUE_CORE_API_KEY` - shared ingestion key used by issue-core and
|
||||
activity-core.
|
||||
- `GITEA_BACKEND_TOKEN` - token for creating issues in cluster Gitea.
|
||||
|
||||
Never write either value to Git, State Hub, workplans, logs, or chat. Record
|
||||
only non-secret evidence such as Secret key count, ExternalSecret readiness,
|
||||
HTTP status codes, and created issue URLs.
|
||||
|
||||
## Build and publish
|
||||
|
||||
Build the checked-out source tree and publish a registry tag that ArgoCD can
|
||||
pull:
|
||||
|
||||
```bash
|
||||
docker build -t forgejo.coulomb.social/coulomb/issue-core:0.2.1 .
|
||||
docker push forgejo.coulomb.social/coulomb/issue-core:0.2.1
|
||||
```
|
||||
|
||||
The Coulomb Gitea package is public-pullable for this image, so the workload
|
||||
does not use an `imagePullSecret`.
|
||||
|
||||
## Pre-sync validation
|
||||
|
||||
From the issue-core repo:
|
||||
|
||||
```bash
|
||||
kubectl kustomize k8s/railiance
|
||||
```
|
||||
|
||||
The rendered resources should be:
|
||||
|
||||
- `ExternalSecret/issue-core-runtime`
|
||||
- `ConfigMap/issue-core-backends`
|
||||
- `Deployment/issue-core`
|
||||
- `Service/issue-core`
|
||||
|
||||
## Sync verification
|
||||
|
||||
After railiance-platform syncs the tenant `Application`:
|
||||
|
||||
```bash
|
||||
kubectl get application issue-core -n argocd
|
||||
kubectl -n issue-core get externalsecret issue-core-runtime
|
||||
kubectl -n issue-core get secret issue-core-runtime
|
||||
kubectl -n issue-core get deploy,pod,svc
|
||||
```
|
||||
|
||||
Expected non-secret evidence:
|
||||
|
||||
- ArgoCD Application reports `Synced` and `Healthy`.
|
||||
- `ExternalSecret/issue-core-runtime` reports Ready.
|
||||
- `Secret/issue-core-runtime` exists with two data keys.
|
||||
- `Deployment/issue-core` has one available replica.
|
||||
- `Service/issue-core` exposes port `8765`.
|
||||
|
||||
Health check from inside the cluster:
|
||||
|
||||
```bash
|
||||
kubectl -n issue-core run issue-core-health --rm -i --restart=Never --image=curlimages/curl:8.8.0 -- http://issue-core:8765/healthz
|
||||
```
|
||||
|
||||
## Ingestion smoke
|
||||
|
||||
Run the authenticated smoke from a short-lived Job so the API key is mounted
|
||||
from the Kubernetes Secret without printing it:
|
||||
|
||||
```bash
|
||||
kubectl -n issue-core delete job issue-core-smoke --ignore-not-found
|
||||
kubectl -n issue-core apply -f - <<'YAML'
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: issue-core-smoke
|
||||
spec:
|
||||
ttlSecondsAfterFinished: 600
|
||||
backoffLimit: 0
|
||||
template:
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: smoke
|
||||
image: curlimages/curl:8.8.0
|
||||
env:
|
||||
- name: ISSUE_CORE_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: issue-core-runtime
|
||||
key: ISSUE_CORE_API_KEY
|
||||
command: ["/bin/sh", "-ceu"]
|
||||
args:
|
||||
- |
|
||||
curl -fsS -X POST "http://issue-core:8765/issues/" -H "Authorization: Bearer ${ISSUE_CORE_API_KEY}" -H "Content-Type: application/json" --data '{"title":"issue-core railiance01 smoke","description":"GitOps smoke created by the issue-core deployment runbook.","target_repo":"coulomb/markitect-main","priority":"low","labels":["smoke","issue-core"],"source_type":"rule","source_id":"issue-core-gitops-smoke","triggering_event_id":"scheduled","activity_definition_id":"issue-core-gitops-smoke"}'
|
||||
YAML
|
||||
kubectl -n issue-core wait --for=condition=complete job/issue-core-smoke --timeout=90s
|
||||
kubectl -n issue-core logs job/issue-core-smoke
|
||||
```
|
||||
|
||||
Acceptance evidence is HTTP 201 plus a response body containing `issue_id`,
|
||||
`backend: "gitea"`, and an `issue_url` for cluster Gitea.
|
||||
|
||||
Cleanup:
|
||||
|
||||
```bash
|
||||
kubectl -n issue-core delete job issue-core-smoke
|
||||
```
|
||||
|
||||
## Activity-core handoff
|
||||
|
||||
After issue-core is Ready and the shared `ISSUE_CORE_API_KEY` is available to
|
||||
activity-core from the same approved OpenBao source:
|
||||
|
||||
- Set `ISSUE_CORE_URL=http://issue-core.issue-core.svc.cluster.local:8765`.
|
||||
- Set `ISSUE_SINK_TYPE=rest`.
|
||||
- Inject the same `ISSUE_CORE_API_KEY` into the activity-core worker.
|
||||
- Keep cron-triggered emissions explicit: `triggering_event_id` may be a stable
|
||||
non-empty scheduler key such as `scheduled`; event-driven emissions should
|
||||
continue to send the event UUID.
|
||||
|
||||
Verify by running an activity-core emission and confirming that issue-core
|
||||
returns HTTP 201 and creates a Gitea issue.
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
# Non-secret backend structure for issue-core on CoulombCore.
|
||||
# Default backend = Forgejo task inbox (Gitea-compatible API). Legacy in-cluster
|
||||
# gitea-http was retired; all coulomb/* repos there are archived (issue create 423).
|
||||
# Token is injected at startup from GITEA_BACKEND_TOKEN (ExternalSecret) — must be
|
||||
# a Forgejo API token with issues:create on the default repo.
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: issue-core-backends
|
||||
namespace: issue-core
|
||||
labels:
|
||||
app.kubernetes.io/name: issue-core
|
||||
app.kubernetes.io/part-of: railiance-gitops
|
||||
data:
|
||||
backends.json: |
|
||||
{
|
||||
"forgejo-inbox": {
|
||||
"type": "gitea",
|
||||
"base_url": "https://forgejo.coulomb.social",
|
||||
"owner": "coulomb",
|
||||
"repo": "the-custodian",
|
||||
"token": "__FROM_ENV__"
|
||||
},
|
||||
"default": "forgejo-inbox"
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: issue-core
|
||||
namespace: issue-core
|
||||
labels:
|
||||
app.kubernetes.io/name: issue-core
|
||||
app.kubernetes.io/part-of: railiance-gitops
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "1" # after the ExternalSecret (wave 0)
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: issue-core
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: issue-core
|
||||
app.kubernetes.io/part-of: railiance-gitops
|
||||
spec:
|
||||
# Image is public-pullable from the Gitea registry (per railiance-forge
|
||||
# docs). Add imagePullSecrets: [{name: gitea-registry}] if it becomes private.
|
||||
containers:
|
||||
- name: issue-core
|
||||
image: forgejo.coulomb.social/coulomb/issue-core:0.2.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8765
|
||||
env:
|
||||
- name: ISSUE_CORE_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: issue-core-runtime
|
||||
key: ISSUE_CORE_API_KEY
|
||||
- name: GITEA_BACKEND_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: issue-core-runtime
|
||||
key: GITEA_BACKEND_TOKEN
|
||||
- name: BACKENDS_TEMPLATE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: issue-core-backends
|
||||
key: backends.json
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 20
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 256Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: false
|
||||
runAsNonRoot: true
|
||||
runAsUser: 10001
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# Runtime secrets for issue-core, materialized from OpenBao by External Secrets
|
||||
# Operator (cluster default per railiance-platform docs/argocd-gitops.md).
|
||||
#
|
||||
# DEPENDENCY: External Secrets Operator is not yet installed on railiance01 and
|
||||
# the OpenBao path below must be provisioned by railiance-platform. Until then
|
||||
# this resource will not reconcile and the Deployment stays Pending the Secret.
|
||||
#
|
||||
# OpenBao path: platform/workloads/issue-core/issue-core/issue-core-runtime
|
||||
# properties: ISSUE_CORE_API_KEY, GITEA_BACKEND_TOKEN
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: issue-core-runtime
|
||||
namespace: issue-core
|
||||
labels:
|
||||
app.kubernetes.io/name: issue-core
|
||||
app.kubernetes.io/part-of: railiance-gitops
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "0" # before the Deployment (wave 1)
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
# Provisioned by railiance-platform during ESO install; name TBC on bootstrap.
|
||||
name: openbao
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: issue-core-runtime
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: ISSUE_CORE_API_KEY
|
||||
remoteRef:
|
||||
key: platform/workloads/issue-core/issue-core/issue-core-runtime
|
||||
property: ISSUE_CORE_API_KEY
|
||||
- secretKey: GITEA_BACKEND_TOKEN
|
||||
remoteRef:
|
||||
key: platform/workloads/issue-core/issue-core/issue-core-runtime
|
||||
property: GITEA_BACKEND_TOKEN
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# issue-core workload manifests, synced by the ArgoCD `issue-core` Application
|
||||
# (path k8s/railiance, destination namespace issue-core, CreateNamespace=true).
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: issue-core
|
||||
|
||||
resources:
|
||||
- externalsecret.yaml
|
||||
- configmap-backends.yaml
|
||||
- deployment.yaml
|
||||
- service.yaml
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# ClusterIP exposing issue-core on 8765 as
|
||||
# issue-core.issue-core.svc.cluster.local:8765 — the address activity-core's
|
||||
# ISSUE_CORE_URL points at once its k8s runtime port is corrected (8010 -> 8765).
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: issue-core
|
||||
namespace: issue-core
|
||||
labels:
|
||||
app.kubernetes.io/name: issue-core
|
||||
app.kubernetes.io/part-of: railiance-gitops
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: issue-core
|
||||
ports:
|
||||
- name: http
|
||||
port: 8765
|
||||
targetPort: http
|
||||
|
|
@ -4,7 +4,7 @@ type: workplan
|
|||
title: "rapp-issue-core: move the runtime off CoulombCore onto railiance01"
|
||||
domain: infotech
|
||||
repo: issue-core
|
||||
status: active
|
||||
status: finished
|
||||
owner: codex
|
||||
lane: yellow
|
||||
topic_slug: issue-core
|
||||
|
|
@ -176,7 +176,7 @@ UV_CACHE_DIR=/tmp/issue-core-rmgr-cache uv run --directory ../repo-manager \
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0007-T02
|
||||
status: progress
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "e0427de0-dfac-4848-ba2d-1421167eb704"
|
||||
```
|
||||
|
|
@ -193,7 +193,7 @@ records by hand.
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0007-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "d6e5e2ac-7f42-412f-8143-91531f5155e8"
|
||||
```
|
||||
|
|
@ -214,7 +214,7 @@ handoff. Two active sources of deployment truth are not allowed.
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0007-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "21974fbd-4962-4732-b407-c531bb2ebfe6"
|
||||
```
|
||||
|
|
@ -240,7 +240,7 @@ That is the condition being retired.
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0007-T05
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "3fdbd9ab-3e3f-4ac0-8763-77278a1cc6e6"
|
||||
```
|
||||
|
|
@ -263,7 +263,7 @@ still pointed at `127.0.0.1:18765`.
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0007-T06
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "668e37dc-8ebe-46cc-9a27-905440b1240c"
|
||||
```
|
||||
|
|
@ -291,3 +291,24 @@ Remaining CoulombCore services after this: `core-hub-staging` and `inter-hub`.
|
|||
kubeconfig any more — its `k3s-api` tunnel was removed on 2026-08-19, so
|
||||
inspecting the *current* deployment needs that tunnel restored first.
|
||||
- Reviewed 2026-08-19 in issue-core and promoted from `proposed` to `ready`.
|
||||
|
||||
## Completion evidence — 2026-08-19
|
||||
|
||||
- Created, registered, validated, and published private repo
|
||||
`coulomb/rapp-issue-core`; wrapper commit `3003c92`, State Hub workstream
|
||||
`b4c39759-6073-4558-a70c-2f869a31cfca`.
|
||||
- Fixed the Forgejo lifecycle identifier contract in issue-core commit
|
||||
`3523a7d`; published and deployed immutable digest
|
||||
`sha256:a56c80ccbd1690bc0bcea384165b1967704f0fdbaf1c506ce1082f56190b92cf`.
|
||||
- Full wrapper evidence passed: health 200, unauthenticated 401, authenticated
|
||||
create 201 + close 200, bounded dependency 503, recovery 201 + close 200,
|
||||
ExternalSecret ready with two keys, both NetworkPolicies present, previous
|
||||
digest rollback health 200, and restored-digest re-verification.
|
||||
- activity-core commit `213e810` now uses
|
||||
`http://issue-core.issue-core.svc.cluster.local:8765` directly while keeping
|
||||
`ISSUE_SINK_TYPE=state-hub`; a controlled worker-side request returned
|
||||
create 201 and close 200.
|
||||
- Deleted the legacy activity-core bridge resources, stopped and removed both
|
||||
port-18765 ops-bridge entries, and confirmed the local listener was gone.
|
||||
- Retired this repo's duplicate `k8s/railiance/` source and obsolete ArgoCD
|
||||
runbook after the wrapper was pushed and its evidence retained.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue