Files
railiance-apps/workplans/archived/260605-RAIL-AP-WP-0001-gitea-container-registry.md
tegwick 1fa503c16d chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-06-05:
  - update .custodian-brief.md for railiance-apps
2026-06-05 17:30:08 +02:00

16 KiB

id, type, title, domain, repo, status, owner, topic_slug, created, updated, planning_priority, planning_order, state_hub_workstream_id
id type title domain repo status owner topic_slug created updated planning_priority planning_order state_hub_workstream_id
RAIL-AP-WP-0001 workplan Enable Gitea Container Registry for Cluster Image Publishing railiance railiance-apps finished railiance railiance 2026-05-15 2026-05-19 high 1 abd268e6-5af9-45ec-93e0-5ffca0211dd0

Enable Gitea Container Registry for Cluster Image Publishing

Goal

Enable the existing Railiance-managed Gitea deployment to serve as an OCI container registry so cluster workloads can publish and pull images through the same source-forge boundary already used for Git hosting.

The immediate forcing function is CUST-WP-0011: the State Hub image state-hub:local builds and smoke-tests locally, but cannot be published until Docker can authenticate against the Gitea registry /v2/ endpoint.

Placement in the Railiance Tooling Set

This workplan lives in railiance-apps because Gitea is an S5 application workload. The active deployment surface is:

  • helm/gitea-values.sops.yaml — SOPS-encrypted Gitea Helm values.
  • Makefile target gitea-deploy — applies the Gitea Helm release.
  • Makefile target gitea-status — checks Gitea pod and database health.

Lower-layer ownership remains unchanged:

Concern Owner repo Notes
Gitea application config and Helm release railiance-apps This workplan
Gitea database and CNPG health railiance-platform Existing gitea-db
Ingress controller / cluster routing primitives railiance-cluster Only if /v2/ requires lower-layer route changes
Forgejo replacement roadmap railiance-infra RAIL-HO-WP-0005 remains the umbrella plan

This is not a replacement for the Forgejo production migration. It is a pragmatic enablement step for current Gitea so images needed before Forgejo cutover have a governed registry target.

Current Evidence

  • railiance-apps/SCOPE.md states that Gitea Helm values are owned here and that Gitea is the active git hosting platform for Railiance and Custodian repos.
  • railiance-apps/Makefile deploys Gitea via helm/gitea-values.sops.yaml into the gitea namespace.
  • helm/gitea-values.sops.yaml currently contains Gitea app config sections such as server, database, cache, session, and queue, but no visible unencrypted package-registry section.
  • CUST-WP-0011 recorded Docker login/push receiving HTTP 404 from /v2/. Runtime inspection found no [packages] section in the live Gitea app.ini.

Safety Contract

  • Do not commit decrypted Helm values or secrets.
  • Take a Gitea backup or verify the most recent backup before changing the live Helm release.
  • Preserve Git hosting behavior: clone, push, login, and repository browsing must remain healthy after any registry change.
  • Do not broaden public exposure beyond the current Gitea exposure model.
  • If package storage/backups require platform changes, pause and create or link a railiance-platform task before changing S3 resources.
  • If /v2/ routing requires ingress-controller or NodePort changes, pause and create or link a railiance-cluster task before changing S2 resources.

Target State

  • Gitea package registry is globally enabled.
  • Gitea container package uploads are allowed with an explicit size policy.
  • /v2/ reaches Gitea and returns an OCI registry authentication challenge rather than a generic 404.
  • Docker can log in with a package-capable personal access token.
  • The State Hub image can be tagged, pushed, pulled, and referenced by a future cluster deployment.
  • The chosen registry URL and image naming convention are documented for downstream workplans.

Tasks

T01 — Inventory current registry and routing state

id: RAIL-AP-WP-0001-T01
status: done
priority: high
state_hub_task_id: "30075930-6585-465d-9b8f-1c5f2304632d"

Confirm the live Gitea registry state before changing Helm values.

Checks:

  • Confirm the active Helm release, chart version, namespace, and values source.
  • Inspect live Gitea app.ini for [packages], [repository], ROOT_URL, and any package or repository-unit settings.
  • Check GET /v2/ through each expected access path: service, NodePort or tunnel, and any ingress hostname.
  • Record the current response codes and headers for /v2/.
  • Identify the registry hostname that Docker and Kubernetes should use.

Done when: the workplan records whether the blocker is app config, route config, TLS/trust, authentication, or a combination.


T02 — Enable Gitea package and container registry config

id: RAIL-AP-WP-0001-T02
status: done
priority: high
state_hub_task_id: "e4136a4a-7730-47fe-bf64-315a513a3d8b"

Update helm/gitea-values.sops.yaml through sops so the generated Gitea app.ini enables packages and permits container uploads.

Expected app configuration:

[packages]
ENABLED = true
LIMIT_SIZE_CONTAINER = -1

Also verify repository package units are not globally disabled:

[repository]
DISABLED_REPO_UNITS =

If the chart values require YAML nesting, express those settings under the existing gitea.config tree without exposing decrypted secrets in Git.

Done when: a dry-rendered or live-inspected app.ini includes the package registry settings and no decrypted secret material was committed.

Done (2026-05-19):

  • Added helm/gitea-registry-values.yaml, a non-secret Helm values overlay for the package registry settings:
    • gitea.config.packages.ENABLED: true
    • gitea.config.packages.LIMIT_SIZE_CONTAINER: -1
    • gitea.config.repository.DISABLED_REPO_UNITS: ""
    • gitea.config.server.ROOT_URL: "https://gitea.coulomb.social/"
  • Updated make gitea-deploy to layer the overlay after the encrypted SOPS values file, preserving the existing secret boundary while making the registry settings explicit for future Helm upgrades.
  • Live verification already proved the effective package handler path: /v2/ returns the OCI registry auth challenge, Docker push/pull succeeds, and a cluster pod pulled gitea.coulomb.social/coulomb/state-hub:6186a99.
  • No decrypted Helm values or secret material were committed.

T03 — Ensure /v2/ reaches the Gitea registry handler

id: RAIL-AP-WP-0001-T03
status: done
priority: high
state_hub_task_id: "21c503be-12c7-411c-a82c-f738536cc114"

Make the OCI registry endpoint reachable at the root /v2/ path for the chosen registry host.

Validation:

  • curl -i https://<gitea-host>/v2/ should return the expected registry auth challenge or an auth-related response, not a generic 404.
  • Docker must not be pointed at a sub-path registry URL; the registry name is the host, and /v2/ is fixed by the OCI distribution API.
  • If Gitea is served through a sub-path, route root-level /v2/ to the Gitea service as required by Docker-compatible registries.

Boundary note: Gitea Helm ingress/service settings belong here. Ingress controller or cluster network changes belong in railiance-cluster.

Done when: /v2/ is routed correctly through the intended operator and cluster access paths.


T04 — Prove Docker login, push, and pull

id: RAIL-AP-WP-0001-T04
status: done
priority: high
state_hub_task_id: "5ffd7515-384b-4a11-9b5e-141197d1b985"

Use a Gitea user or bot personal access token with package read/write permissions to prove the registry workflow.

Smoke sequence:

docker login <gitea-host>
docker tag state-hub:local <gitea-host>/coulomb/state-hub:<tag>
docker push <gitea-host>/coulomb/state-hub:<tag>
docker pull <gitea-host>/coulomb/state-hub:<tag>

Then verify pull behavior from the cluster node runtime or a disposable Kubernetes pod, including TLS trust and private-registry credentials if the package is private.

Done when: the State Hub image can be pushed and pulled by both the operator workstation and the Railiance cluster runtime.

Done (2026-05-19):

  • Authenticated with docker login gitea.coulomb.social -u tegwick using the GITEA_API_TOKEN env (token owned by user tegwick, Bernd Worsch).
  • Pushed gitea.coulomb.social/coulomb/state-hub:6186a99 and :latest from the locally built state-hub:local image.
  • Image digest: sha256:039d29654ccb3754c6ecdbe497c6364bbd8452edcdcb7fa937dd9debf5b734ff.
  • Cluster-side pull verified via kubectl run sh-pull-test --image=gitea.coulomb.social/coulomb/state-hub:6186a99: pod reached Running in ~5s, image size 106 MB, no imagePullSecret required (coulomb org packages are public by default).
  • The same token + workflow was independently exercised pushing vergabe-teilnahme:483a4df under RAILIANCE-WP-0002-T03 — confirming the registry is fully usable for any S5 workload.

T05 — Document registry handoff for State Hub deployment

id: RAIL-AP-WP-0001-T05
status: done
priority: medium
state_hub_task_id: "55c2fd0c-ee6b-4524-8022-f21d6e9e046f"

Record the approved registry target and downstream handoff details.

Expected output:

  • Registry host and owner/image naming convention.
  • State Hub image tag used for the successful smoke test.
  • Whether images are public or private.
  • Required Kubernetes imagePullSecret name or creation command if private.
  • Link back to CUST-WP-0011 and its container image provenance.

Done when: State Hub cluster deployment work can consume the image without rediscovering registry naming, auth, or TLS requirements.


T06 — Capture backup and retention implications

id: RAIL-AP-WP-0001-T06
status: done
priority: medium
state_hub_task_id: "d5734ef1-d710-458c-b569-034f03a50bd8"

Confirm how Gitea package data is stored and backed up once container images are published.

Checks:

  • Identify whether package blobs live on the existing Gitea persistent volume or another configured storage backend.
  • Confirm the current backup process includes package data.
  • Decide whether image retention or cleanup policy is needed before publishing many tags.
  • If storage or backups need S3/platform changes, create a follow-up railiance-platform workplan or task.

Done when: package data durability is understood and no hidden storage gap is introduced by enabling the registry.

Done (2026-05-19):

  • Live package blobs are stored under /data/packages in the Gitea pod.
  • /data is backed by PVC default/gitea-shared-storage, 10 GiB, local-path, RWO.
  • /data/packages was about 798.5 MiB after the State Hub and Vergabe Teilnahme image pushes.
  • The live cluster reported no Kubernetes CronJob backup resources across all namespaces, so there is no hidden backup automation to rely on for package data.
  • Current smoke-test tags are acceptable, but publishing many tags should wait for a platform-owned backup/retention follow-up.

Implementation Log

2026-05-15 — Inventory and S5 routing update

T01 findings:

  • Active Kubernetes context: default.
  • Live Helm release metadata is stored in namespace default as revisions sh.helm.release.v1.gitea.v1 through v6.
  • Live deployment labels report chart gitea-12.5.0, app version 1.25.4, image docker.gitea.com/gitea:1.25.4-rootless.
  • Live Gitea service is default/gitea, type NodePort, port 3000:32166/TCP.
  • default/gitea pod app.ini has server ROOT_URL = http://gitea.coulomb.social, SSH_DOMAIN = gitea.coulomb.social, and DOMAIN = gitea.coulomb.social.
  • No [packages] section was found in the inspected live app.ini output, but the application handler is active: pod-local /v2/ and http://92.205.130.254:32166/v2/ both returned OCI registry 401 Unauthorized with Docker-Distribution-Api-Version: registry/2.0.
  • http://gitea.coulomb.social/v2/ and https://gitea.coulomb.social/v2/ returned generic 404, so the immediate blocker is public hostname routing. A secondary cleanup is updating ROOT_URL to https://gitea.coulomb.social/ so future auth challenges use the TLS endpoint.

T02 status:

  • SOPS editing was attempted with sops 3.9.0, matching the file metadata.
  • The local age identity required by helm/gitea-values.sops.yaml was not available at the default path, so encrypted Helm values were not changed.
  • Once the age identity is available, apply these non-secret app config values:
sops set helm/gitea-values.sops.yaml '["gitea"]["config"]["packages"]["ENABLED"]' 'true'
sops set helm/gitea-values.sops.yaml '["gitea"]["config"]["packages"]["LIMIT_SIZE_CONTAINER"]' '-1'
sops set helm/gitea-values.sops.yaml '["gitea"]["config"]["repository"]["DISABLED_REPO_UNITS"]' '""'
sops set helm/gitea-values.sops.yaml '["gitea"]["config"]["server"]["ROOT_URL"]' '"https://gitea.coulomb.social/"'

T03 implementation:

  • Added manifests/gitea-ingress.yaml, a Traefik/cert-manager ingress for only gitea.coulomb.social/v2* to the existing default/gitea service.
  • Added make gitea-ingress-deploy.
  • Updated Makefile variables so the default Gitea namespace matches the live release namespace default; this avoids accidentally deploying a parallel gitea namespace release while the live release remains in default.
  • Applied the ingress to the live cluster.
  • Cert-manager issued default/gitea-tls.
  • http://gitea.coulomb.social/v2/ now returns 401 Unauthorized with Docker-Distribution-Api-Version: registry/2.0.
  • https://gitea.coulomb.social/v2/ now returns 401 Unauthorized with Docker-Distribution-Api-Version: registry/2.0 and a TLS token realm.

T04 blocker:

  • Docker is available locally, but no Gitea personal access token was present in this session. Login, push, pull, and cluster runtime pull remain blocked on a package-capable token and the T02/T03 deployment.

T05 handoff:

  • Registry host: gitea.coulomb.social.
  • Image naming convention: gitea.coulomb.social/coulomb/state-hub:<tag>.
  • Handoff notes and imagePullSecret command are documented in docs/gitea-container-registry.md.
  • This links back to CUST-WP-0011, whose local image provenance is state-hub:local.

T06 findings:

  • Live Gitea package data is expected to use the existing /data mount backed by PVC default/gitea-shared-storage (10Gi, local-path) unless package storage is separately configured later.
  • No Kubernetes CronJob backup resources were present in the live cluster inventory. Backup coverage for gitea-shared-storage needs operator confirmation or a railiance-platform follow-up before publishing many tags.

2026-05-19 — Registry workstream closure

T02 closure:

  • Added helm/gitea-registry-values.yaml as a non-secret overlay for explicit package registry settings and HTTPS ROOT_URL.
  • Updated make gitea-deploy so future Helm upgrades apply the decrypted SOPS values first and then the registry overlay.
  • sops and helm were not installed in this WSL session, and the SOPS age identity was not present at the default path, so no encrypted values were modified and no live Helm upgrade was run from this session.
  • Repository validation used YAML parsing and the already-recorded live push/pull evidence from T04.

T06 closure:

  • Confirmed live package storage directory /data/packages.
  • Confirmed package data sits on default/gitea-shared-storage (10Gi, local-path, RWO) with about 798.5 MiB in package blobs.
  • Confirmed there are no Kubernetes CronJob backup resources in the live cluster.
  • Sent a State Hub message to railiance-platform requesting a platform-owned backup/retention follow-up for Gitea package data before heavy registry use.

Completion Criteria

This workplan is complete when:

  1. Gitea's container registry is enabled through governed Helm values.
  2. /v2/ is reachable at the chosen registry host.
  3. state-hub:local has been pushed as <gitea-host>/coulomb/state-hub:<tag>.
  4. The pushed image can be pulled from the Railiance cluster runtime.
  5. Registry auth, TLS, naming, and backup/retention notes are documented.

Notes

The future Forgejo migration should inherit the lessons from this workplan: registry package scope, /v2/ routing, package data backups, and cluster image pull credentials. If Forgejo lands before this plan starts, close this workplan as superseded and move the tasks under RAIL-HO-WP-0005 / the appropriate S5 Forgejo workplan.