openova/platform/gitea
e3mrah 66abe75b2e
fix(bp-gitea): mirror gitea-admin-secret to catalyst ns via reflector annotations (#844)
Live failure on otech103 2026-05-04: cutover Step-1 gitea-mirror Job in catalyst ns CrashLoops with 'secret "gitea-admin-secret" not found' because K8s forbids cross-namespace secretKeyRef. The Secret created by bp-gitea 1.2.4 lives in the gitea ns; the cutover Job runs in the catalyst ns.

Fix: add reflector.v1.k8s.emberstack.com annotations on the Secret so bp-reflector (already installed at slot 05a) mirrors it into the catalyst namespace. The Job's secretKeyRef then resolves locally. Reflector keeps the mirror in lockstep on password rotation.

Bumps bp-gitea 1.2.4 → 1.2.5 + slot 10 pin lockstep.

Co-authored-by: Hatice Yildiz <hatice.yildiz@openova.io>
2026-05-05 00:37:04 +04:00
..
chart fix(bp-gitea): mirror gitea-admin-secret to catalyst ns via reflector annotations (#844) 2026-05-05 00:37:04 +04:00
blueprint.yaml fix(bp-gitea): ship gitea-admin-secret with random password (#830) (#832) 2026-05-04 23:26:55 +04:00
README.md docs(seaweedfs+guacamole): replace MinIO with SeaweedFS as unified S3 encapsulation; add Guacamole to bp-relay 2026-04-28 10:23:46 +02:00

Gitea

Per-Sovereign Git server for Catalyst. Hosts the public Blueprint catalog mirror, Org-private Blueprints, and per-Environment Gitea repos.

Status: Accepted | Updated: 2026-04-27

Catalyst role: Per-Sovereign supporting service in the Catalyst control plane (one Gitea per Sovereign on the management cluster). See docs/PLATFORM-TECH-STACK.md §2.3 and docs/ARCHITECTURE.md §3.


Overview

Gitea provides self-hosted Git with CI/CD capabilities:

  • Internal Git repository hosting (per-Sovereign).
  • Gitea Actions (GitHub Actions compatible).
  • HA via intra-cluster replicas (not cross-region mirror — see Multi-Region section below).
  • CNPG PostgreSQL backend.

Architecture

flowchart TB
    subgraph Gitea["Gitea"]
        Web[Web UI]
        Git[Git Server]
        Actions[Gitea Actions]
    end

    subgraph Backend["Backend"]
        CNPG[CNPG Postgres]
        SeaweedFS[SeaweedFS Storage]
    end

    subgraph Integrations
        Flux[Flux CD]
        Console[Catalyst console]
    end

    Web --> CNPG
    Git --> CNPG
    Actions --> SeaweedFS
    Flux -->|"Clone"| Git
    Console -->|"Discover"| Git

Multi-Region Strategy

Catalyst runs one Gitea per Sovereign on the management cluster. Cross-region resilience comes from intra-cluster HA (multiple replicas + CNPG primary-replica), not cross-region bidirectional mirror.

flowchart TB
    subgraph Mgt["Management cluster (per Sovereign)"]
        G[Gitea — N replicas, HA]
        PG[CNPG primary]
        PGR[CNPG read-replica]
        G --> PG
        PG -.->|"WAL streaming"| PGR
    end

    subgraph Region1["Workload region 1"]
        F1[Per-vcluster Flux]
    end

    subgraph Region2["Workload region 2"]
        F2[Per-vcluster Flux]
    end

    G --> F1
    G --> F2

Why not cross-region bidirectional mirror?

  • Single source of truth simplifies the merge story (the Sovereign-wide Catalyst console writes once, all Flux instances pull from one place).
  • Bidirectional mirror would create write-conflict semantics that complicate EnvironmentPolicy enforcement (which requires PR approvals to be authoritative on the destination repo).
  • Workload region failures don't affect Gitea — Flux is read-mostly during outages and the management cluster is the primary failure domain to harden.

If the Sovereign needs Gitea continuity across a full management-cluster failure, the relevant pattern is a DR replica of the management cluster — not Gitea mirroring inside one Sovereign.


Configuration

Gitea Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gitea
  namespace: gitea
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: gitea
          image: gitea/gitea:1.21
          env:
            - name: GITEA__database__DB_TYPE
              value: postgres
            - name: GITEA__database__HOST
              value: gitea-postgres-rw.databases.svc:5432
            - name: GITEA__storage__STORAGE_TYPE
              value: seaweedfs
            - name: GITEA__storage__SEAWEEDFS_ENDPOINT
              value: seaweedfs.storage.svc:8333

Mirror Configuration

# app.ini
[mirror]
ENABLED = true
DISABLE_NEW_PULL = false
DISABLE_NEW_PUSH = false
DEFAULT_INTERVAL = 1m

Gitea Actions

GitHub Actions compatible CI/CD:

# .gitea/workflows/ci.yaml
name: CI
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: make build
      - name: Test
        run: make test

Actions Runner

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gitea-runner
  namespace: gitea
spec:
  replicas: 2
  template:
    spec:
      containers:
        - name: runner
          image: gitea/act_runner:latest
          env:
            - name: GITEA_INSTANCE_URL
              value: https://gitea.<location-code>.<sovereign-domain>
            - name: GITEA_RUNNER_REGISTRATION_TOKEN
              valueFrom:
                secretKeyRef:
                  name: gitea-runner-token
                  key: token

Integration Points

Integration Purpose
Flux CD GitOps source repository
Catalyst console Repository discovery, templates
External Secrets Token management
CNPG PostgreSQL database
SeaweedFS LFS and Actions storage

Backup

Gitea data is backed up via:

  • CNPG for PostgreSQL (WAL streaming to async standby; backed up via Velero to SeaweedFS + cloud archival).
  • SeaweedFS replication for LFS/Actions storage.
  • Velero scheduled backups of the gitea namespace.

Part of OpenOva