diff --git a/Makefile b/Makefile index 70c4277..f847034 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,8 @@ GITEA_CHART ?= gitea-charts/gitea GITEA_VALUES ?= helm/gitea-values.sops.yaml GITEA_REGISTRY_VALUES ?= helm/gitea-registry-values.yaml GITEA_INGRESS ?= manifests/gitea-ingress.yaml +GITEA_HTTP_SERVICE ?= gitea-http +GITEA_SSH_SERVICE ?= gitea-ssh-nodeport GITEA_DB_CLUSTER ?= gitea-db GITEA_DB_NAMESPACE ?= databases REGISTRY_DOCS ?= docs/gitea-container-registry.md docs/gitea-package-registry.md @@ -89,7 +91,8 @@ gitea-ingress-deploy: ## Apply the public Gitea HTTPS ingress 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 svc -n $(GITEA_NAMESPACE) $(GITEA_HTTP_SERVICE) --ignore-not-found + kubectl get svc -n $(GITEA_NAMESPACE) $(GITEA_SSH_SERVICE) --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); \ diff --git a/SCOPE.md b/SCOPE.md index 55909ff..dd2e827 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -117,7 +117,8 @@ The Fabric graph declarations for forge capabilities and edges live in - Implementation: repository contract, registry docs, initial operating contracts, deploy-capable Gitea files, and operator targets are present. - Stability: emerging but now live-facing; forge owns the reviewed public - Gitea HTTPS ingress for the web UI, package registry, and OCI registry. + Gitea HTTPS ingress for the web UI, package registry, and OCI registry. Raw + node IP HTTP access is not part of the supported forge surface. - Usage: canonical reference point for forge and registry responsibilities currently transitioning out of `railiance-apps`. diff --git a/docs/gitea-actions-runner-evidence.md b/docs/gitea-actions-runner-evidence.md index 0c93332..7505834 100644 --- a/docs/gitea-actions-runner-evidence.md +++ b/docs/gitea-actions-runner-evidence.md @@ -80,7 +80,7 @@ Observed on 2026-06-07: | live runner process | PID `5911` after activation | | registration file | `/root/.runner`, mode `0644`, owner `root:root` | | registration name | `haskelseed` | -| registration address | `http://92.205.130.254:32166` | +| historical registration address | `http://92.205.130.254:32166` before the public NodePort was retired under `FORGE-WP-0005` | | registration labels before activation | `haskelseed:host`, `linux:host`, `x86_64:host` | | registration labels after activation | `self-hosted:host`, `haskelseed:host`, `linux:host`, `linux_amd64:host`, `x86_64:host`, `container-build:host`, `registry-publish:host` | | ephemeral | `false` | @@ -146,8 +146,8 @@ Run from an operator host with registry access: ```bash for tag in 91037a4 ae9e497 fa96fb8 7cc3173 latest; do - skopeo inspect --tls-verify=false \ - "docker://92.205.130.254:32166/coulomb/inter-hub:${tag}" \ + skopeo inspect \ + "docker://gitea.coulomb.social/coulomb/inter-hub:${tag}" \ --format "${tag} {{.Name}} {{.Digest}}" done ``` diff --git a/docs/gitea-container-registry.md b/docs/gitea-container-registry.md index 5c88ccc..5282e55 100644 --- a/docs/gitea-container-registry.md +++ b/docs/gitea-container-registry.md @@ -10,6 +10,8 @@ Use `gitea.coulomb.social` as the approved forge and registry host. The public ingress serves the Gitea web route at `https://gitea.coulomb.social/`, the OCI registry route at `/v2`, and the Python package route at `/api/packages`. The `/v2` route returns the OCI registry authentication challenge over HTTPS. +Do not use raw node IP HTTP ports for web or registry traffic; the Gitea HTTP +Service is internal-only and the public standard is the HTTPS host. Registry-specific Gitea settings are carried in `helm/gitea-registry-values.yaml`, a non-secret overlay applied after the SOPS diff --git a/docs/gitea-package-registry.md b/docs/gitea-package-registry.md index 17b54ce..986ab28 100644 --- a/docs/gitea-package-registry.md +++ b/docs/gitea-package-registry.md @@ -17,6 +17,7 @@ reconcile the Gitea Helm release with `helm/gitea-registry-values.yaml` so Status on 2026-06-13: the root web route returns `200`, live `ROOT_URL` is `https://gitea.coulomb.social/`, and package artifact links render HTTPS URLs. +Raw node IP HTTP access is not a supported package or web entry point. ## Python Packages diff --git a/docs/observability-operating-evidence.md b/docs/observability-operating-evidence.md index 5e348e3..3a70f31 100644 --- a/docs/observability-operating-evidence.md +++ b/docs/observability-operating-evidence.md @@ -57,6 +57,10 @@ curl -i https://gitea.coulomb.social/v2/ curl -i https://gitea.coulomb.social/api/packages/coulomb/pypi/simple/ ``` +The raw node IP HTTP NodePort is intentionally not part of the public health +surface. Treat any reachable `http://:/` web route as +a regression to close, not as an alternate supported endpoint. + Git SSH: - If a Git SSH endpoint is published, verify it with a read-only `git ls-remote` diff --git a/helm/gitea-registry-values.yaml b/helm/gitea-registry-values.yaml index 74020a4..23596f4 100644 --- a/helm/gitea-registry-values.yaml +++ b/helm/gitea-registry-values.yaml @@ -1,4 +1,11 @@ -# Non-secret Gitea registry settings layered after the SOPS values file. +# Non-secret Gitea public endpoint and registry settings layered after the SOPS +# values file. +service: + http: + # Public web/API access is provided by manifests/gitea-ingress.yaml. + # Keep the Service internal so the raw node IP:port path is not a + # supported or reachable Gitea entry point. + type: ClusterIP gitea: config: packages: diff --git a/manifests/gitea-ingress.yaml b/manifests/gitea-ingress.yaml index b799778..9db5c7a 100644 --- a/manifests/gitea-ingress.yaml +++ b/manifests/gitea-ingress.yaml @@ -20,21 +20,21 @@ spec: pathType: Prefix backend: service: - name: gitea + name: gitea-http port: number: 3000 - path: /v2 pathType: Prefix backend: service: - name: gitea + name: gitea-http port: number: 3000 - path: / pathType: Prefix backend: service: - name: gitea + name: gitea-http port: number: 3000 tls: diff --git a/workplans/FORGE-WP-0005-remove-gitea-nodeport-side-door.md b/workplans/FORGE-WP-0005-remove-gitea-nodeport-side-door.md new file mode 100644 index 0000000..f2cfb1d --- /dev/null +++ b/workplans/FORGE-WP-0005-remove-gitea-nodeport-side-door.md @@ -0,0 +1,97 @@ +--- +id: FORGE-WP-0005 +type: workplan +title: "Remove public Gitea NodePort side door" +domain: railiance +repo: railiance-forge +status: finished +owner: codex +topic_slug: railiance +planning_priority: high +created: "2026-06-14" +updated: "2026-06-14" +state_hub_workstream_id: "d6af707c-d9b1-463b-b24e-b384c5fb390d" +--- + +# Remove public Gitea NodePort side door + +## Context + +After `FORGE-WP-0004`, `https://gitea.coulomb.social/` is the canonical public +Gitea endpoint. The legacy `default/gitea` Service still exposed HTTP through +NodePort `32166`, which made `http://92.205.130.254:32166/` look like a second +Gitea entry point. It reached the same pod and database, but it bypassed the +canonical HTTPS host and created operator confusion. + +## T01 - Make the HTTP Service internal-only + +```task +id: FORGE-WP-0005-T01 +status: done +priority: high +state_hub_task_id: "1ab4f7d0-0eef-4618-84d9-a84d72db9629" +``` + +Set the non-secret Gitea Helm overlay to `service.http.type: ClusterIP` so the +chart-supported `gitea-http` Service stays internal-only and the web/API surface +is only public through the forge-owned HTTPS ingress. Keep Git SSH exposure +separate and unchanged. + +## T02 - Reconcile live Gitea and verify the side door is gone + +```task +id: FORGE-WP-0005-T02 +status: done +priority: high +state_hub_task_id: "34a9759e-10f1-4202-b8e9-443265495022" +``` + +Apply a pinned chart `--reuse-values` Helm reconciliation that keeps the +chart-supported HTTP service internal-only while preserving the existing Gitea +app version and HTTPS `ROOT_URL`. Move the ingress backend to `gitea-http`, then +delete the legacy `default/gitea` NodePort Service because it is no longer part +of the current chart's supported public endpoint model. + +Verify: + +- `default/gitea` is absent and `default/gitea-http` is internal-only; +- `http://92.205.130.254:32166/` is no longer reachable; +- `https://gitea.coulomb.social/` still returns `200`; +- `/api/v1/version` still returns the live Gitea version; +- `/v2/` still returns the OCI authentication challenge; +- the package-specific PyPI simple index for `issue-core` still returns `200`. + +Completed on 2026-06-14. A pinned Helm `--reuse-values` reconciliation kept +chart `gitea-12.5.0`, app `1.25.4`, and +`gitea.config.server.ROOT_URL=https://gitea.coulomb.social/` while setting +`service.http.type=ClusterIP`. The forge ingress backend was moved from the +legacy `gitea` Service to the chart-supported internal `gitea-http` Service, +then the legacy `default/gitea` NodePort Service was deleted. + +Verification evidence: + +- `kubectl get svc -n default -l app.kubernetes.io/instance=gitea` lists + `gitea-http` as `ClusterIP`, `gitea-ssh` as `ClusterIP`, and + `gitea-ssh-nodeport` for Git SSH only; the legacy `gitea` Service is absent; +- `http://92.205.130.254:32166/` timed out; +- `https://gitea.coulomb.social/` returned `200`; +- `https://gitea.coulomb.social/api/v1/version` returned `200`; +- `https://gitea.coulomb.social/v2/` returned `401`, preserving the OCI auth + challenge; +- `https://gitea.coulomb.social/api/packages/coulomb/pypi/simple/issue-core/` + returned `200`. + +## T03 - Sync State Hub and record closure evidence + +```task +id: FORGE-WP-0005-T03 +status: done +priority: medium +state_hub_task_id: "0f9f6b29-aeef-4558-a5f8-d1039a136224" +``` + +Run State Hub consistency sync for `railiance-forge`, record a progress note, +and keep the repo docs clear that raw HTTP NodePort access is not a supported +Gitea entry point. + +Completed on 2026-06-14 after live verification.