diff --git a/AGENTS.md b/AGENTS.md index 0e23cb2..93e3256 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -95,6 +95,23 @@ curl -s -X PATCH "http://127.0.0.1:8000/tasks/" \ - Record significant decisions via `POST /decisions/`. - Keep forge responsibilities separate from S4 templates and S5 app releases. +## Verification Commands + +This repo currently contains documentation, workplans, and read-only operator +entry points. There is no app build, package install, or unit-test command yet. + +Use these checks for ordinary edits: + +```bash +git diff --check +make registry-docs +make check-tools +make -C /home/worsch/state-hub fix-consistency REPO=railiance-forge +``` + +`make gitea-status` is read-only but requires a kubeconfig pointed at a +representative Railiance cluster. + **Close:** 1. Update workplan file task statuses. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d491c3c --- /dev/null +++ b/Makefile @@ -0,0 +1,56 @@ +SHELL := /usr/bin/env bash +.DEFAULT_GOAL := help + +GITEA_RELEASE ?= gitea +GITEA_NAMESPACE ?= default +GITEA_DB_CLUSTER ?= gitea-db +GITEA_DB_NAMESPACE ?= databases +REGISTRY_DOCS ?= docs/gitea-container-registry.md docs/gitea-package-registry.md + +##@ Operator checks + +check-tools: ## Check local tools used by forge operator targets + @missing=0; \ + for tool in kubectl helm sops; do \ + if command -v $$tool >/dev/null 2>&1; then \ + echo "ok: $$tool"; \ + else \ + echo "missing: $$tool"; \ + missing=1; \ + fi; \ + done; \ + if command -v tea >/dev/null 2>&1; then \ + echo "ok: tea"; \ + else \ + echo "optional: tea not found"; \ + fi; \ + exit $$missing + +registry-docs: ## Print canonical registry docs + @for doc in $(REGISTRY_DOCS); do \ + printf '\n## %s\n\n' "$$doc"; \ + sed -n '1,220p' "$$doc"; \ + done + +##@ Current Gitea + +gitea-status: ## Read-only status for current Gitea runtime and database + kubectl get pods -n $(GITEA_NAMESPACE) -l app.kubernetes.io/instance=$(GITEA_RELEASE) + kubectl get svc -n $(GITEA_NAMESPACE) $(GITEA_RELEASE) --ignore-not-found + kubectl get ingress -n $(GITEA_NAMESPACE) $(GITEA_RELEASE) --ignore-not-found + @if kubectl cnpg status $(GITEA_DB_CLUSTER) -n $(GITEA_DB_NAMESPACE) >/dev/null 2>&1; then \ + kubectl cnpg status $(GITEA_DB_CLUSTER) -n $(GITEA_DB_NAMESPACE); \ + else \ + echo "kubectl cnpg plugin not available; falling back to cnpg resources"; \ + kubectl get cluster $(GITEA_DB_CLUSTER) -n $(GITEA_DB_NAMESPACE); \ + kubectl get pods -n $(GITEA_DB_NAMESPACE) -l cnpg.io/cluster=$(GITEA_DB_CLUSTER); \ + fi + +##@ Help + +help: ## Show this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} \ + /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } \ + /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(MAKEFILE_LIST) + +.PHONY: check-tools registry-docs gitea-status help diff --git a/README.md b/README.md index 554038a..6368331 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,18 @@ Start with: 1. `INTENT.md` 2. `SCOPE.md` 3. `AGENTS.md` -4. `workplans/` +4. `docs/` +5. `workplans/` -Current implementation status: founding. No live Gitea files have been migrated -from `railiance-apps` yet. +Current implementation status: early extraction. Canonical registry operation +docs and read-only status targets live here now. Deploy-capable Gitea Helm, +SOPS, and manifest files remain in `railiance-apps` until the explicit +migration review in `RAILIANCE-WP-0006-T03`. + +Useful entry points: + +```bash +make registry-docs +make check-tools +make gitea-status +``` diff --git a/SCOPE.md b/SCOPE.md index 9ca067c..cefeb9c 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -29,8 +29,9 @@ The practical contract is: paths; 4. `railiance-apps` consumes forge artifacts and deploys user-facing workloads. -No live Gitea files have been migrated here yet. This repo is being founded as -the future home for that operational surface. +Canonical registry operation docs and read-only forge checks now live here. +Deploy-capable Gitea Helm/SOPS/manifests remain in `railiance-apps` until the +explicit migration gate for live-affecting files is reviewed. --- @@ -104,16 +105,20 @@ the future home for that operational surface. ## Current State -- Status: founding. -- Implementation: repository contract and first workplan are being created. -- Stability: emerging. -- Usage: intended as the new home for forge responsibilities currently - visible in `railiance-apps`. +- Status: early extraction. +- Implementation: repository contract, registry docs, initial operating + contracts, and read-only operator targets are present. +- Stability: emerging but non-disruptive; no deploy-capable Gitea state has + moved yet. +- Usage: canonical reference point for forge and registry responsibilities + currently transitioning out of `railiance-apps`. Known starting point: - `railiance-apps` currently owns Gitea Helm values, registry overlays, ingress, - Gitea Makefile targets, and registry docs. + and deploy-capable Gitea Makefile targets. +- `railiance-forge` owns registry operation docs, operating contracts, and + read-only status entry points. - `railiance-enablement` owns the intent for delivery templates and developer paved paths, but not forge runtime operation. - `railiance-forge` should absorb forge runtime and artifact infrastructure @@ -167,7 +172,9 @@ Known starting point: 2. Read `INTENT.md` for stable purpose. 3. Read this file for scope and boundaries. 4. Read active files in `workplans/`. -5. For migration context, read +5. For registry operations, read `docs/gitea-container-registry.md` and + `docs/gitea-package-registry.md`. +6. For migration context, read `/home/worsch/railiance-apps/workplans/RAILIANCE-WP-0006-railiance-forge-extraction.md`. --- diff --git a/docs/first-migration-plan.md b/docs/first-migration-plan.md index e80ff6c..ce38df7 100644 --- a/docs/first-migration-plan.md +++ b/docs/first-migration-plan.md @@ -2,6 +2,9 @@ Date: 2026-06-05 +Status: Phase 1 is underway. The remote repository exists and is pushed, so the +earlier Gitea API blocker no longer applies. + This plan starts the extraction of forge ownership from `railiance-apps` into `railiance-forge` without changing the live Gitea deployment. @@ -85,7 +88,7 @@ Review gates: - `railiance-forge` remote exists and is pushed. - State Hub workplans are synced in both repos. -- Operator confirms the Gitea token/remote creation issue is fixed. +- Operator confirms deploy-capable Gitea ownership should move now. - `railiance-apps` has compatibility pointers for old paths. - The plan distinguishes current Gitea operation from future Forgejo cutover. @@ -112,19 +115,13 @@ Validation: - `railiance-apps` no longer claims forge runtime ownership. - App operators can still find registry instructions through pointers. -## Open Blocker +## Remote Status -The local `tea` login named `coulomb` is configured but currently fails with -`invalid username, password or token`. This blocks creation of the remote -`coulomb/railiance-forge` repository through the Gitea API. - -Until refreshed credentials are available: - -- keep `railiance-forge` local and State Hub-registered; -- do not add an `origin` remote that points to a missing repository; -- avoid claiming remote publication is complete. +`railiance-forge` now has `origin` configured as +`gitea-remote:coulomb/railiance-forge.git` and the local `main` branch is +aligned with `origin/main`. ## Next Recommended Action -Proceed with Phase 1 documentation canonicalization after the operator confirms -that compatibility pointers in `railiance-apps` are acceptable. +Complete Phase 1 documentation canonicalization and Phase 2 read-only operator +targets, then review the deploy-capable Gitea file move separately. diff --git a/docs/gitea-container-registry.md b/docs/gitea-container-registry.md new file mode 100644 index 0000000..644230d --- /dev/null +++ b/docs/gitea-container-registry.md @@ -0,0 +1,84 @@ +# Gitea Container Registry + +This is the canonical Railiance operating note for the current Gitea container +registry. Compatibility pointers remain in `railiance-apps` while deploy-capable +Gitea Helm and manifest files still live there. + +## Registry Target + +Use `gitea.coulomb.social` as the approved registry host. The `/v2` ingress is +live as of 2026-05-15 and returns the OCI registry authentication challenge over +HTTPS. + +Registry-specific Gitea settings are currently carried in +`/home/worsch/railiance-apps/helm/gitea-registry-values.yaml`, a non-secret +overlay applied after the SOPS values file by `make gitea-deploy`. It explicitly +enables packages, permits container and PyPI uploads without an app-level size +cap, clears globally disabled repo units, and moves `ROOT_URL` to the HTTPS +host. + +Image names should use the Gitea owner and package path: + +```bash +gitea.coulomb.social/coulomb/state-hub: +``` + +The State Hub handoff from `CUST-WP-0011` should publish the locally verified +`state-hub:local` image under that name. + +The successful smoke-test tags were: + +```bash +gitea.coulomb.social/coulomb/state-hub:6186a99 +gitea.coulomb.social/coulomb/state-hub:latest +``` + +Digest: + +```text +sha256:039d29654ccb3754c6ecdbe497c6364bbd8452edcdcb7fa937dd9debf5b734ff +``` + +## Operator Smoke Test + +Use a Gitea personal access token with package read/write permission: + +```bash +docker login gitea.coulomb.social +docker tag state-hub:local gitea.coulomb.social/coulomb/state-hub: +docker push gitea.coulomb.social/coulomb/state-hub: +docker pull gitea.coulomb.social/coulomb/state-hub: +``` + +The `coulomb` organization packages are public by default, so the verified +cluster pull for `state-hub:6186a99` did not require an `imagePullSecret`. + +For private packages, create an image pull secret in each consuming namespace: + +```bash +kubectl create secret docker-registry gitea-registry \ + --docker-server=gitea.coulomb.social \ + --docker-username= \ + --docker-password= \ + --namespace= +``` + +Reference it from workloads as `imagePullSecrets: [{name: gitea-registry}]`. + +## Python Packages + +The same Gitea package service is used for Python wheels. See +`docs/gitea-package-registry.md` for the publish/install recipe and the +`issue-core` migration notes from `RAILIANCE-WP-0004 I03`. + +## Current Storage Notes + +The live Gitea pod mounts `gitea-shared-storage` at `/data`; package blobs land +under `/data/packages`. On 2026-05-19 that package directory was about +798.5 MiB. + +The PVC is `default/gitea-shared-storage`, 10 GiB, `local-path`, `RWO`. The live +cluster showed no Kubernetes `CronJob` backup resources across namespaces on +2026-05-19. This is acceptable for the current smoke-test images, but heavy tag +growth should wait for the forge/platform backup and retention follow-up in +`docs/initial-operating-contracts.md`. diff --git a/docs/gitea-package-registry.md b/docs/gitea-package-registry.md new file mode 100644 index 0000000..8e7ee5c --- /dev/null +++ b/docs/gitea-package-registry.md @@ -0,0 +1,50 @@ +# Gitea Package Registry + +This is the canonical Railiance operating note for the current Gitea Python +package registry. Compatibility pointers remain in `railiance-apps` while +deploy-capable Gitea Helm and manifest files still live there. + +Gitea package support is enabled by +`/home/worsch/railiance-apps/helm/gitea-registry-values.yaml`. That overlay is +applied after the encrypted base values by `make gitea-deploy` and enables both +container packages and Python packages. + +## Python Packages + +Publish Python wheels to the organization package endpoint: + +```bash +python -m build +TWINE_USERNAME= \ +TWINE_PASSWORD= \ +python -m twine upload \ + --repository-url https://gitea.coulomb.social/api/packages/coulomb/pypi \ + dist/* +``` + +Install from the simple index: + +```bash +pip install \ + --extra-index-url https://:@gitea.coulomb.social/api/packages/coulomb/pypi/simple/ \ + issue-core +``` + +For CI, store the token as a secret and inject it into the package index URL at +build time. Do not commit tokenized index URLs. + +## issue-core Migration + +The portable deployment path for `vergabe-teilnahme` is: + +1. Release `issue-core` from its source repo as a wheel, for example `0.2.0`. +2. Publish the wheel to the Gitea Python package registry. +3. Keep `vergabe-teilnahme/pyproject.toml` on a versioned dependency such as + `issue-core>=0.2,<0.3`. +4. Regenerate `vergabe-teilnahme/uv.lock` from the Gitea PyPI registry after the + package exists there. +5. Build the image on a clean runner that has no sibling `issue-core` checkout. + +Registry endpoint ownership lives in `railiance-forge`; the package release and +application dependency lock belong to the `issue-core` and `vergabe-teilnahme` +source repos. diff --git a/docs/initial-operating-contracts.md b/docs/initial-operating-contracts.md new file mode 100644 index 0000000..25760bd --- /dev/null +++ b/docs/initial-operating-contracts.md @@ -0,0 +1,89 @@ +# Initial Forge Operating Contracts + +Last reviewed: 2026-06-05 + +These contracts are the first explicit boundary for the Railiance forge layer. +They are intentionally operational enough to guide the next file moves, while +leaving live deploy and secret custody changes behind separate review gates. + +## Status + +- Contract maturity: draft v1. +- Live impact: none; this document does not authorize a deploy or cutover. +- Current forge runtime: Gitea at `gitea.coulomb.social`. +- Future migration target: Forgejo, under a separate cutover workplan. + +## Artifact Lifecycle And Provenance + +- Source repositories own build definitions, package metadata, and release + versioning. +- `railiance-forge` owns the registry endpoints, registry operating docs, + retention posture, and artifact evidence model. +- `railiance-apps` consumes already-published artifacts in S5 release values and + runbooks. +- Container images should publish immutable commit-SHA tags for release + evidence. Mutable tags such as `latest` are allowed only as convenience + pointers and must not be the sole production reference. +- Python packages should use versioned releases. Internal consumers should pin + compatible ranges in source repos and regenerate locks after the package is + published. +- Release evidence should capture source repo, commit SHA, artifact name, + version/tag, smoke result, and consuming deployment value change. + +## Retention And Cleanup + +- Smoke-test image tags can be pruned after a newer validated smoke tag exists + and no rollback or diagnosis still references them. +- Production image tags and Python package versions should be retained for at + least the active rollback window of every consuming deployment. +- Deleting a package or image is an operator action, not an automated default, + until package restore has been drilled. +- The current Gitea package data lives under `/data/packages` on the + `default/gitea-shared-storage` PVC. On 2026-05-19 it was about 798.5 MiB of a + 10 GiB `local-path` volume. +- Growth inspection belongs in forge operations; durable backup implementation + belongs with the platform storage/database layer. + +## Runner Substrate Ownership + +- `railiance-forge` owns Gitea/Forgejo Actions runner deployment, runner labels, + runner placement, runner credentials, and runner health evidence. +- `railiance-enablement` owns reusable workflow templates, paved paths, and + developer-facing automation conventions. +- Application repos own app-specific workflows and build scripts. +- `railiance-apps` owns S5 release checks for app manifests and deployment + values, but not the runner substrate those checks execute on. +- Runner secret access must be explicit by label, repository, and workflow + purpose. Broad package or cluster credentials should not be shared across + unrelated jobs. + +## Backup And Restore Handoff + +- `railiance-forge` defines what must be restorable: Git repositories, package + blobs, registry metadata, runner configuration, and source-forge application + state. +- `railiance-platform` owns the reusable database, object-storage, backup, and + restore mechanisms used by forge workloads. +- Forge data should not become production-critical without a recorded restore + drill for the relevant storage path. +- S5 app releases may consume forge artifacts, but they should cite forge + evidence rather than owning package blob backup procedures themselves. + +## Secret Custody + +- This repo may reference secret names, SOPS file paths, OpenBao paths, and + operator procedures. +- This repo must not commit decrypted secret values, package tokens, runner + tokens, tokenized package index URLs, or generated credential material. +- Deploy-capable files that reference encrypted values move only after review of + the SOPS/OpenBao handoff and compatibility pointers. + +## Observability And Evidence + +- `make gitea-status` is the first read-only operator check in this repo. +- Forge health should cover web, Git SSH, container registry, Python package + registry, database, package storage, and runner status. +- Downstream app release evidence should cite forge artifact evidence rather + than repeating registry implementation details. +- Future monitoring should turn the manual status checks into durable signals + once the Railiance observability layer is ready. diff --git a/workplans/FORGE-WP-0001-repository-foundation.md b/workplans/FORGE-WP-0001-repository-foundation.md index 8f9c046..b34676e 100644 --- a/workplans/FORGE-WP-0001-repository-foundation.md +++ b/workplans/FORGE-WP-0001-repository-foundation.md @@ -4,7 +4,7 @@ type: workplan title: "railiance-forge repository foundation" domain: railiance repo: railiance-forge -status: active +status: finished owner: codex topic_slug: railiance planning_priority: high @@ -115,7 +115,7 @@ file move. ```task id: FORGE-WP-0001-T05 -status: todo +status: done priority: medium state_hub_task_id: "a5924b97-ccf7-4da0-acea-4f6017fef278" ``` @@ -129,3 +129,6 @@ Create first draft contracts for: - basic forge observability. Done when follow-on implementation work can be split into focused workplans. + +Completed in `docs/initial-operating-contracts.md`, with read-only operator +entry points in `Makefile` and follow-on migration tracked in `FORGE-WP-0002`. diff --git a/workplans/FORGE-WP-0002-registry-docs-and-readonly-ops.md b/workplans/FORGE-WP-0002-registry-docs-and-readonly-ops.md new file mode 100644 index 0000000..25938bc --- /dev/null +++ b/workplans/FORGE-WP-0002-registry-docs-and-readonly-ops.md @@ -0,0 +1,98 @@ +--- +id: FORGE-WP-0002 +type: workplan +title: "Canonical registry docs and read-only forge operations" +domain: railiance +repo: railiance-forge +status: active +owner: codex +topic_slug: railiance +planning_priority: high +created: "2026-06-05" +updated: "2026-06-05" +state_hub_workstream_id: "00c57adc-b8e6-46d6-a963-d6847646a6b0" +--- + +# Canonical registry docs and read-only forge operations + +## Context + +The `railiance-forge` remote now exists and the repository is synced with +State Hub. The first safe extraction step is to move registry operating +knowledge and read-only inspection targets before moving deploy-capable Gitea +configuration from `railiance-apps`. + +## T01 - Adopt canonical Gitea registry docs + +```task +id: FORGE-WP-0002-T01 +status: done +priority: high +state_hub_task_id: "16fa09f4-f8fe-4d73-a9b1-7611bbf13dc9" +``` + +Move canonical container and Python package registry operation notes into +`railiance-forge/docs/`, leaving compatibility pointers in `railiance-apps`. + +Done when operators can find registry endpoints, credential handling, package +publish/install recipes, and current storage notes in this repo. + +--- + +## T02 - Add read-only operator targets + +```task +id: FORGE-WP-0002-T02 +status: done +priority: high +state_hub_task_id: "977af707-e455-4669-aeb5-62ccf31a8d55" +``` + +Add a forge-side `Makefile` with: + +- `make registry-docs`; +- `make check-tools`; +- `make gitea-status`. + +Done when the new repo can inspect current Gitea state without owning +deploy-capable Helm or Kubernetes apply commands. + +--- + +## T03 - Prepare deploy-capable Gitea move review + +```task +id: FORGE-WP-0002-T03 +status: todo +priority: high +state_hub_task_id: "58a8073d-4665-4cf6-a1f8-e4810c7d392d" +``` + +Review the next candidate move from `railiance-apps`: + +- `helm/gitea-values.sops.yaml`; +- `helm/gitea-registry-values.yaml`; +- `manifests/gitea-ingress.yaml`; +- `releases/gitea/values.yaml`; +- `make gitea-deploy`; +- `make gitea-ingress-deploy`. + +Done when the move plan is specific enough to preserve secret boundaries, +operator compatibility, and live Gitea stability. + +--- + +## T04 - Re-home parent workplan references + +```task +id: FORGE-WP-0002-T04 +status: done +priority: medium +state_hub_task_id: "bc0daafa-0b01-479b-9f46-79c6d8fe1c0e" +``` + +Update `railiance-apps` docs and workplans so registry operation points to +`railiance-forge`, while app release runbooks stay in S5. + +Done when the old app-side registry docs are compatibility pointers instead of +competing canonical sources. diff --git a/workplans/archived/260605-RAILIANCE-WP-0001-statehub-bootstrap.md b/workplans/archived/260605-RAILIANCE-WP-0001-statehub-bootstrap.md index c6be697..f08e6d8 100644 --- a/workplans/archived/260605-RAILIANCE-WP-0001-statehub-bootstrap.md +++ b/workplans/archived/260605-RAILIANCE-WP-0001-statehub-bootstrap.md @@ -4,7 +4,7 @@ type: workplan title: "Bootstrap State Hub integration" domain: railiance repo: railiance-forge -status: ready +status: archived owner: codex topic_slug: railiance created: "2026-06-05" @@ -14,13 +14,18 @@ state_hub_workstream_id: "96ff8f40-fc3d-4f48-94e4-c862f2eb866b" # Bootstrap State Hub integration -This file defines what `railiance-forge` owns, when to use it, and where its boundaries stop. +This generated bootstrap plan records the initial State Hub onboarding for +`railiance-forge`. + +It is archived because the generated files have been reviewed, repo-specific +instructions are present, and `FORGE-WP-0001` now carries the real repository +foundation work. ## Review Generated Integration Files ```task id: RAILIANCE-WP-0001-T01 -status: todo +status: done priority: high state_hub_task_id: "695cbdcc-ff69-4b83-9611-1080ae5a46ef" ``` @@ -32,7 +37,7 @@ Replace generated placeholders with repo-specific facts where needed. ```task id: RAILIANCE-WP-0001-T02 -status: todo +status: done priority: high state_hub_task_id: "60d01b85-1b82-49d0-9a19-f4147f12348f" ``` @@ -45,7 +50,7 @@ changes confidently. ```task id: RAILIANCE-WP-0001-T03 -status: todo +status: done priority: medium state_hub_task_id: "41d82631-86fb-4c2f-813d-305e0e18eab6" ```