diff --git a/Makefile b/Makefile index 8877ace..56ed59c 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,6 @@ SHELL := /usr/bin/env bash .DEFAULT_GOAL := help -GITEA_RELEASE ?= gitea -GITEA_NAMESPACE ?= default -FORGE_REPO ?= /home/worsch/railiance-forge - VERGABE_RELEASE ?= vergabe-teilnahme VERGABE_NAMESPACE ?= vergabe-teilnahme VERGABE_CHART ?= charts/vergabe-teilnahme @@ -18,7 +14,7 @@ VERGABE_DB_HOST ?= apps-pg-rw.databases VERGABE_DB_PORT ?= 5432 VERGABE_DB_NAME ?= vergabe_db -SOPS_SENTINEL ?= $(FORGE_REPO)/helm/gitea-values.sops.yaml +SOPS_SENTINEL ?= DRY_RUN_CREATE_NAMESPACES ?= false ##@ Operator checks @@ -26,23 +22,12 @@ DRY_RUN_CREATE_NAMESPACES ?= false check-tools: ## Check required operator tools and warn about optional diagnostics tools/check-tools.sh -check-sops: ## Verify the local SOPS age key can decrypt the configured sentinel - SOPS_SENTINEL=$(SOPS_SENTINEL) tools/check-sops.sh +check-sops: ## Verify the local SOPS age key can decrypt SOPS_SENTINEL + SOPS_SENTINEL="$(SOPS_SENTINEL)" tools/check-sops.sh k8s-server-dry-run: ## Server-side dry-run rendered Helm and committed manifests DRY_RUN_CREATE_NAMESPACES=$(DRY_RUN_CREATE_NAMESPACES) tools/k8s-server-dry-run.sh -##@ Gitea compatibility - -gitea-deploy: ## Compatibility wrapper; Gitea deploy ownership moved to railiance-forge - $(MAKE) -C $(FORGE_REPO) GITEA_RELEASE=$(GITEA_RELEASE) GITEA_NAMESPACE=$(GITEA_NAMESPACE) gitea-deploy - -gitea-ingress-deploy: ## Compatibility wrapper; Gitea ingress ownership moved to railiance-forge - $(MAKE) -C $(FORGE_REPO) GITEA_RELEASE=$(GITEA_RELEASE) GITEA_NAMESPACE=$(GITEA_NAMESPACE) gitea-ingress-deploy - -gitea-status: ## Compatibility wrapper; Gitea status ownership moved to railiance-forge - $(MAKE) -C $(FORGE_REPO) GITEA_RELEASE=$(GITEA_RELEASE) GITEA_NAMESPACE=$(GITEA_NAMESPACE) gitea-status - apps-pg-status: ## Check the shared apps-pg cnpg cluster @if kubectl cnpg status apps-pg -n databases >/dev/null 2>&1; then \ kubectl cnpg status apps-pg -n databases; \ @@ -99,4 +84,4 @@ help: ## Show this help /^[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 check-sops k8s-server-dry-run gitea-deploy gitea-ingress-deploy gitea-status apps-pg-status vergabe-dry-run vergabe-deploy vergabe-ingress-deploy vergabe-status vergabe-migrate vergabe-seed vergabe-superuser vergabe-logs vergabe-db-url-secret help +.PHONY: check-tools check-sops k8s-server-dry-run apps-pg-status vergabe-dry-run vergabe-deploy vergabe-ingress-deploy vergabe-status vergabe-migrate vergabe-seed vergabe-superuser vergabe-logs vergabe-db-url-secret help diff --git a/SCOPE.md b/SCOPE.md index 1f668c2..810d38a 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -45,8 +45,8 @@ intent, the current implementation is aligned around: - keep application release concerns in S5 while respecting S1-S4 ownership; - provide enough runbook and guardrail coverage that the next app does not rediscover the same deployment traps; -- consume the current Gitea/registry surface through the `railiance-forge` - boundary instead of owning forge runtime state in S5. +- consume forge-owned source and registry capabilities through the + `railiance-forge` boundary instead of owning forge runtime state in S5. The remaining gap is not the absence of intent; it is turning the first-app lessons into reusable S5 app release patterns. @@ -55,15 +55,8 @@ lessons into reusable S5 app release patterns. ## In Scope -- Transitional Gitea compatibility wrappers: - - `make gitea-deploy`; - - `make gitea-ingress-deploy`; - - `make gitea-status`; - - each delegates to `/home/worsch/railiance-forge`. -- App-side registry consumption pointers: - - `docs/gitea-container-registry.md`; - - `docs/gitea-package-registry.md`; - - canonical operating docs in `/home/worsch/railiance-forge/docs/`. +- Consumption of forge-owned source and registry capabilities from S5 app + release docs and values, without owning forge runtime configuration. - `vergabe-teilnahme` as the first concrete S5 application release: - chart in `charts/vergabe-teilnahme/`; - values in `helm/vergabe-teilnahme-values.yaml`; @@ -130,11 +123,13 @@ lessons into reusable S5 app release patterns. ## Current State - Gitea is deployed and operational as the current forge. Its deploy-capable - Helm/SOPS/manifests now live in `railiance-forge`; this repo keeps - transitional Makefile wrappers only. + Helm/SOPS/manifests now live in `railiance-forge`; this repo no longer keeps + Gitea deploy/status wrappers or registry pointer docs. - The Gitea container and Python package registry paths are verified. Canonical - registry operating docs now live in `railiance-forge`; app-side files here are - compatibility pointers. + registry operating docs live in `railiance-forge`; S5 runbooks link to those + docs directly when app releases consume forge artifacts. +- The final source-of-truth decision for forge ownership is recorded in + `docs/forge-source-of-truth-decision.md`. - The `issue-core` migration is still blocked on publishing `issue-core==0.2.0` with package credentials in the `issue-core` repo and refreshing the `vergabe-teilnahme` lock in its source repo. @@ -152,8 +147,6 @@ lessons into reusable S5 app release patterns. ## Known Gaps And Opportunities -- S5 app docs should continue shedding residual forge-runtime details and link - to forge-owned operating contracts. - The first-app lessons from `vergabe-teilnahme` are documented, but there is no reusable "new S5 app release checklist" yet. - The manifest dry-run workflow assumes access to a representative cluster and @@ -212,8 +205,8 @@ from that file. source forge, registry, package registry, runner substrate, and artifact evidence belong to `railiance-forge`; this repo consumes those capabilities. - Potentially confusing terms: - "deployment" here means app release deployment unless a command explicitly - delegates to `railiance-forge` for current Gitea operation. + "deployment" here means app release deployment. Forge runtime deployment and + registry operation belong to `railiance-forge`. --- @@ -238,7 +231,7 @@ from that file. type: infrastructure title: S5 application workload deployment description: Deploy and operate user-facing Railiance applications as Helm releases and Kubernetes manifests, including app release guardrails and the first Django S5 app release. -keywords: [railiance, s5, gitea, registry, helm, django, vergabe-teilnahme, workload, deployment] +keywords: [railiance, s5, registry-consumer, helm, django, vergabe-teilnahme, workload, deployment] ``` ```capability @@ -256,11 +249,12 @@ keywords: [operator, runbook, sops, cnpg, dry-run, smoke-test, deployment] 2. Read `INTENT.md` for the stable purpose of the S5 layer. 3. Read this file for scope and boundaries. 4. Read the active files in `workplans/`. -5. For Gitea registry work, start with +5. For Gitea registry work, use the forge-owned docs directly: `/home/worsch/railiance-forge/docs/gitea-container-registry.md` and - `/home/worsch/railiance-forge/docs/gitea-package-registry.md`; the local - files are compatibility pointers. + `/home/worsch/railiance-forge/docs/gitea-package-registry.md`. 6. For `vergabe-teilnahme`, start with `docs/vergabe-teilnahme.md`, then inspect `charts/vergabe-teilnahme/`, `helm/vergabe-teilnahme-values.yaml`, and `manifests/vergabe-teilnahme-ingress.yaml`. -7. Run `make check-tools` and `make check-sops` before deploy work. +7. Run `make check-tools` before deploy work. Run + `SOPS_SENTINEL= make check-sops` when app release work + touches encrypted SOPS files. diff --git a/docs/forge-source-of-truth-decision.md b/docs/forge-source-of-truth-decision.md new file mode 100644 index 0000000..74bde4b --- /dev/null +++ b/docs/forge-source-of-truth-decision.md @@ -0,0 +1,33 @@ +# Forge Source Of Truth Decision + +Date: 2026-06-05 + +## Decision + +`railiance-forge` is the source of truth for current Gitea operation, future +Forgejo migration, forge runtime deployment, source hosting, container and +Python package registries, Actions runner substrate, artifact retention, and +forge operating evidence. + +`railiance-apps` consumes those forge capabilities only as release +infrastructure for S5 application workloads. It does not keep Gitea +deploy/status wrappers, forge SOPS sentinels, registry-retention procedures, or +local compatibility copies of forge registry docs. + +## Rationale + +The forge layer is cross-cutting infrastructure for source control, packages, +images, runners, and promotion evidence. Keeping it in S5 made app release +runbooks responsible for non-app runtime state. The dedicated forge repo gives +operators one place to change forge runtime behavior while allowing S5 app +runbooks to cite forge evidence and consume published artifacts. + +## Consequences + +- Forge runtime changes start in `/home/worsch/railiance-forge`. +- S5 app release work links to forge docs instead of duplicating registry or + runner operating procedures. +- App-specific charts, values, manifests, smoke tests, and runbooks remain in + `/home/worsch/railiance-apps`. +- Source repos still own application code, package metadata, package publishing, + image build definitions, and lock regeneration. diff --git a/docs/gitea-container-registry.md b/docs/gitea-container-registry.md deleted file mode 100644 index 5693a45..0000000 --- a/docs/gitea-container-registry.md +++ /dev/null @@ -1,16 +0,0 @@ -# Gitea Container Registry - -Canonical registry operating guidance now lives in: - -```text -/home/worsch/railiance-forge/docs/gitea-container-registry.md -``` - -This compatibility pointer remains in `railiance-apps` after deploy-capable -Gitea Helm, SOPS, and manifest files moved to `railiance-forge` under -`RAILIANCE-WP-0006-T03`. - -Use `railiance-forge` for registry endpoints, package-token handling, smoke -evidence, storage notes, retention posture, and future Forgejo registry -ownership. Use `railiance-apps` only for S5 app release values and app runbooks -that consume already-published images. diff --git a/docs/gitea-package-registry.md b/docs/gitea-package-registry.md deleted file mode 100644 index abf4a0f..0000000 --- a/docs/gitea-package-registry.md +++ /dev/null @@ -1,16 +0,0 @@ -# Gitea Package Registry - -Canonical package-registry operating guidance now lives in: - -```text -/home/worsch/railiance-forge/docs/gitea-package-registry.md -``` - -This compatibility pointer remains in `railiance-apps` after deploy-capable -Gitea Helm, SOPS, and manifest files moved to `railiance-forge` under -`RAILIANCE-WP-0006-T03`. - -Use `railiance-forge` for the Gitea PyPI endpoint, package-token handling, -publish/install recipes, retention posture, and future Forgejo package -ownership. Use `railiance-apps` only for S5 app release values and app runbooks -that consume already-published packages. diff --git a/docs/operator-setup.md b/docs/operator-setup.md index 340e67b..7ab9537 100644 --- a/docs/operator-setup.md +++ b/docs/operator-setup.md @@ -1,10 +1,16 @@ # Operator Setup -Run these checks before deploying or rotating any S5 workload: +Run these checks before deploying any S5 workload: ```bash make check-tools -make check-sops +``` + +When the app release work touches encrypted SOPS files, also verify the +operator age identity against the encrypted file being changed: + +```bash +SOPS_SENTINEL= make check-sops ``` ## Required Tools @@ -27,7 +33,7 @@ for primary/replica health and backup state. ## SOPS Age Key Bootstrap -SOPS-encrypted values in this repo expect an age identity at: +SOPS-encrypted values used by app release work expect an age identity at: ```text ~/.config/sops/age/keys.txt @@ -46,9 +52,9 @@ Bootstrap procedure: ```bash chmod 600 ~/.config/sops/age/keys.txt ``` -5. Verify decryption: +5. Verify decryption against the encrypted file being changed: ```bash - make check-sops + SOPS_SENTINEL= make check-sops ``` Do not commit age identities, decrypted values, or copied SOPS plaintext diff --git a/tools/check-sops.sh b/tools/check-sops.sh index a6d81d4..fa32be5 100755 --- a/tools/check-sops.sh +++ b/tools/check-sops.sh @@ -1,9 +1,15 @@ #!/usr/bin/env bash set -euo pipefail -SOPS_SENTINEL="${SOPS_SENTINEL:-helm/gitea-values.sops.yaml}" +SOPS_SENTINEL="${SOPS_SENTINEL:-}" SOPS_AGE_KEY_FILE="${SOPS_AGE_KEY_FILE:-$HOME/.config/sops/age/keys.txt}" +if [[ -z "$SOPS_SENTINEL" ]]; then + echo "ERROR: SOPS_SENTINEL is not set" >&2 + echo "Set SOPS_SENTINEL to the encrypted file you want to verify." >&2 + exit 1 +fi + if ! command -v sops >/dev/null 2>&1; then echo "ERROR: sops is not installed" >&2 exit 1 diff --git a/workplans/RAILIANCE-WP-0005-s5-app-release-readiness.md b/workplans/RAILIANCE-WP-0005-s5-app-release-readiness.md index 2d284dc..f588bbe 100644 --- a/workplans/RAILIANCE-WP-0005-s5-app-release-readiness.md +++ b/workplans/RAILIANCE-WP-0005-s5-app-release-readiness.md @@ -19,9 +19,9 @@ state_hub_workstream_id: "685f1c18-33c0-400d-a2b1-e1dae0f27c3e" The 2026-06-04 review of `SCOPE.md` against the actual repository implementation found that `railiance-apps` has moved beyond "Gitea Helm values" -and now owns the repeatable S5 application release surface: Gitea registry -enablement, the `vergabe-teilnahme` Helm release, operator guardrails, and -deployment runbooks. +and now owns the repeatable S5 application release surface: forge-backed +artifact consumption, the `vergabe-teilnahme` Helm release, operator +guardrails, and deployment runbooks. The 2026-06-05 `railiance-forge` extraction moved canonical registry operating docs and registry-retention policy into the new forge layer. This workplan now @@ -34,7 +34,7 @@ The same review found several gaps: tied to the old local `issue-core` build context. - First-app lessons are documented, but there is no reusable checklist for the next S5 app release. -- Gitea package storage and app database backup responsibilities need clearer +- Forge package storage and app database backup responsibilities need clearer contracts with platform-layer work. - The server-side dry-run workflow does not state its live-cluster/CRD prerequisites clearly enough for a future runner. @@ -57,7 +57,7 @@ It should explain: - why this repo exists as the S5 application deployment surface; - what problem it solves for operators and source app repos; - what it intentionally does not own across S1-S4 boundaries; -- how Gitea, package registry enablement, `vergabe-teilnahme`, and future S5 +- how forge-owned registry capabilities, `vergabe-teilnahme`, and future S5 apps fit together; - how workplan files relate to State Hub workstreams and task rows. @@ -84,14 +84,15 @@ Focus areas: - document the package-registry credential path for private Python package installs without committing tokenized index URLs; - state when `vergabe-teilnahme/uv.lock` must be regenerated in the source repo; -- keep `docs/gitea-package-registry.md` focused on the S5 registry endpoint and - cross-link source-repo release docs instead of duplicating them. +- link to forge-owned registry endpoint docs and source-repo release docs + instead of duplicating them in S5. Done when the Railiance operator docs describe the portable image promotion path and no active runbook tells an operator to rely on a sibling repo checkout. Completed on 2026-06-05 by updating `docs/vergabe-teilnahme.md` and replacing -the local registry docs with compatibility pointers to `railiance-forge`. +local registry ownership with direct links to `railiance-forge`. The temporary +compatibility pointers were removed later by `RAILIANCE-WP-0006-T10`. --- @@ -178,7 +179,7 @@ PR checks or still needs runner/cluster preparation. --- -## T06 - Define Gitea package registry storage and retention posture +## T06 - Hand off Gitea package registry storage and retention posture ```task id: RAILIANCE-WP-0005-T06 @@ -187,8 +188,8 @@ priority: medium state_hub_task_id: "382ba252-0f54-45fa-8e33-e656f4472341" ``` -Document the operating posture for Gitea package storage while Gitea remains the -active forge. +Document the forge-owned operating posture for Gitea package storage while +Gitea remains the active forge. Include: @@ -199,9 +200,8 @@ Include: - handoff to platform backup/restore work when package data becomes production critical. -Done when registry growth is no longer only a note in -`docs/gitea-container-registry.md`. +Done when registry growth is no longer only a note in S5 app docs. Completed on 2026-06-05 by moving the canonical storage and retention posture -to `/home/worsch/railiance-forge/docs/initial-operating-contracts.md`; the local -registry docs are compatibility pointers. +to `/home/worsch/railiance-forge/docs/initial-operating-contracts.md`; S5 app +runbooks now cite forge docs directly. diff --git a/workplans/RAILIANCE-WP-0006-railiance-forge-extraction.md b/workplans/RAILIANCE-WP-0006-railiance-forge-extraction.md index 42684d2..73d9e4a 100644 --- a/workplans/RAILIANCE-WP-0006-railiance-forge-extraction.md +++ b/workplans/RAILIANCE-WP-0006-railiance-forge-extraction.md @@ -4,7 +4,7 @@ type: workplan title: "Extract railiance-forge and formalize forge-layer contracts" domain: railiance repo: railiance-apps -status: active +status: finished owner: codex topic_slug: railiance planning_priority: high @@ -158,8 +158,9 @@ compatibility pointers left in `railiance-apps`. Deploy-capable Gitea Helm/SOPS/manifests and Makefile deploy/status targets also moved to `railiance-forge` after the review in `/home/worsch/railiance-forge/docs/deploy-capable-gitea-move-review.md`. -`railiance-apps` now keeps compatibility wrappers only. No live deploy, SOPS -decryption, or Kubernetes apply was run. +`railiance-apps` temporarily kept compatibility wrappers until +`RAILIANCE-WP-0006-T10`. No live deploy, SOPS decryption, or Kubernetes apply +was run. --- @@ -196,7 +197,7 @@ Done when a new operator can answer "is this S4, S5, or forge?" from the scope documents without inspecting historical workplans. Completed 2026-06-05: `railiance-apps/SCOPE.md` now treats forge as an upstream -service and keeps only compatibility wrappers for moved Gitea operations. +service and keeps app release ownership separate from moved Gitea operations. `railiance-enablement/SCOPE.md` and `railiance-enablement/INTENT.md` now separate reusable S4 workflow templates and paved paths from forge-owned runtime, registries, runner substrate, labels, credentials, and artifact @@ -385,7 +386,7 @@ cycle. Validation passed with `0 error(s), 0 warning(s)`. ```task id: RAILIANCE-WP-0006-T10 -status: todo +status: done priority: medium state_hub_task_id: "5bca2a11-453c-4cd0-b86a-7ed269564dfb" ``` @@ -404,3 +405,10 @@ Steps: Done when no active railiance workplan asks operators to modify forge runtime state from the wrong repo. + +Completed 2026-06-05: removed the app-side Gitea deploy/status compatibility +wrappers, deleted local registry pointer docs, changed `make check-sops` to +require an explicit `SOPS_SENTINEL`, refreshed active workplans so package +registry and token ownership point to `railiance-forge` and source repos, +archived `RAIL-AP-WP-0001`, and recorded the final source-of-truth decision in +`docs/forge-source-of-truth-decision.md` and State Hub. diff --git a/workplans/archived/260605-RAIL-AP-WP-0001-gitea-container-registry.md b/workplans/archived/260605-RAIL-AP-WP-0001-gitea-container-registry.md index 2113a93..07ffa3b 100644 --- a/workplans/archived/260605-RAIL-AP-WP-0001-gitea-container-registry.md +++ b/workplans/archived/260605-RAIL-AP-WP-0001-gitea-container-registry.md @@ -4,11 +4,11 @@ type: workplan title: "Enable Gitea Container Registry for Cluster Image Publishing" domain: railiance repo: railiance-apps -status: finished +status: archived owner: railiance topic_slug: railiance created: "2026-05-15" -updated: "2026-05-19" +updated: "2026-06-05" planning_priority: high planning_order: 1 state_hub_workstream_id: "abd268e6-5af9-45ec-93e0-5ffca0211dd0" diff --git a/workplans/railiance-apps-WP-0004-app-deployment-improvements.md b/workplans/railiance-apps-WP-0004-app-deployment-improvements.md index 295bbf8..1f81960 100644 --- a/workplans/railiance-apps-WP-0004-app-deployment-improvements.md +++ b/workplans/railiance-apps-WP-0004-app-deployment-improvements.md @@ -9,7 +9,7 @@ owner: railiance topic_slug: railiance planning_priority: medium created: "2026-05-19" -updated: "2026-05-23" +updated: "2026-06-05" state_hub_workstream_id: "b61a9aca-4e43-4b3d-a48b-999e0fa842cf" --- @@ -20,7 +20,7 @@ This workplan collects concrete follow-ups surfaced while shipping independent, and can be picked up in isolation when the next S5 app lands or when the next operator onboards. Activated on 2026-05-22; local railiance-apps guardrails are implemented, with the package -publication item blocked on Gitea package publish credentials. +publication item blocked on forge-owned Gitea package publish credentials. ## I01 — URL-encode DB passwords at Secret-build time @@ -102,15 +102,17 @@ proper wheel with version, and switch the dep to `issue-core>=0.2,<0.3` with a normal index URL. The Dockerfile then drops the `--build-context` and the build becomes portable. -**Coordination:** depends on Gitea PyPI enablement in `railiance-apps` -(small Helm values change) and a release pipeline for `issue-core` -(separate repo). +**Coordination:** depends on the forge-owned Gitea PyPI endpoint and package +token posture in `railiance-forge`, plus a release pipeline for `issue-core` +in its source repo. -**Local progress 2026-05-22.** `helm/gitea-registry-values.yaml` now -sets `packages.LIMIT_SIZE_PYPI: -1`, and -`docs/gitea-package-registry.md` documents the Gitea PyPI endpoint plus -the `issue-core` migration. The remaining release and dependency change -must happen in the `issue-core` and `vergabe-teilnahme` repos. +**Local progress 2026-05-22.** `helm/gitea-registry-values.yaml` set +`packages.LIMIT_SIZE_PYPI: -1` while Gitea was still operated from this repo. +That registry operating surface has since moved to `railiance-forge`; current +PyPI endpoint docs live at +`/home/worsch/railiance-forge/docs/gitea-package-registry.md`. The remaining +release and dependency change must happen in the `issue-core` and +`vergabe-teilnahme` repos. **Cross-repo progress 2026-05-23.** `issue-core` now has a validated `make package-check` build and Gitea Actions publish workflow for the @@ -171,8 +173,9 @@ decrypt a known sentinel would catch this at the first deploy attempt rather than at the failing apply. **Implemented 2026-05-22.** Added `docs/operator-setup.md`, -`tools/check-sops.sh`, and `make check-sops` using -`helm/gitea-values.sops.yaml` as the sentinel by default. +`tools/check-sops.sh`, and `make check-sops`. After the forge extraction, +`make check-sops` requires an explicit `SOPS_SENTINEL=` so this +repo does not depend on forge-owned Gitea SOPS files. --- @@ -239,7 +242,8 @@ wraps the pattern. ## Notes - Items were activated on 2026-05-22. Local railiance-apps pieces are - complete except I03, which is blocked on Gitea package publish credentials. + complete except I03, which is blocked on forge-owned Gitea package publish + credentials and source-repo release work. - I06 is genuinely cross-repo; the others are local to `railiance-apps` or its operator workflow. - The first three items (I01, I02, I03) are the highest-leverage