From 5d7301c4d2ea782365a0de115f56ad29923caf4e Mon Sep 17 00:00:00 2001 From: Thore Cimbal Date: Thu, 13 Aug 2026 12:00:00 +0000 Subject: [PATCH] feat(wiki): git-storage sync to Gitea (ADR-0015) Wiki.js cannot reach git.lab from the cluster, so its content syncs to Gitea (sorb/ThreadNetWiki) over HTTPS with a dedicated deploy PAT; a CI job canonizes Gitea->git.lab (TURN-rotation pattern). The config job's ensure_git_storage configures the git storage target (mode sync, config values {v:...}-encoded like the auth strategy). Repo/user/branch/author are plain env; only the PAT lives in the SOPS secret wikijs-git-secret, wired optional so the job still runs without it. --- apps/production/kustomization.yaml | 1 + apps/production/wikijs-config.py | 33 ++++++++++++++++++++++++++ apps/production/wikijs-config.yaml | 19 +++++++++++++++ apps/production/wikijs-git-secret.yaml | 22 +++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 apps/production/wikijs-git-secret.yaml diff --git a/apps/production/kustomization.yaml b/apps/production/kustomization.yaml index a5cc235..451d674 100644 --- a/apps/production/kustomization.yaml +++ b/apps/production/kustomization.yaml @@ -57,6 +57,7 @@ resources: - wikijs-postgres-secret.yaml # SOPS, von sorb angelegt - wikijs-admin-secret.yaml # SOPS, randomisiert — Bootstrap durch den Konfig-Job - wikijs-oidc-secret.yaml # SOPS, client_id/secret für die OIDC-Strategy + - wikijs-git-secret.yaml # SOPS, Git-Storage-PAT nach Gitea (ADR-0015) - wikijs-postgres.yaml - wikijs.yaml - wiki-ingress.yaml diff --git a/apps/production/wikijs-config.py b/apps/production/wikijs-config.py index 8c4f824..a6264c1 100644 --- a/apps/production/wikijs-config.py +++ b/apps/production/wikijs-config.py @@ -202,6 +202,38 @@ def ensure_theming(jwt: str): log("Theming gesetzt (Dark-Default, Logo + Login-Hintergrund aus gemounteten Assets)") +def ensure_git_storage(jwt: str): + # Git-Storage: Wiki.js-Inhalt nach Gitea syncen (ADR-0015). Der Cluster erreicht + # git.lab nicht -> Gitea ist das Ziel, ein CI-Job kanonisiert Gitea->git.lab. + # Nur der PAT (GIT_STORAGE_TOKEN) ist ein Secret; Repo/User/Branch sind Klartext. + # Fehlt der Token, wird der Schritt übersprungen -> der Job bleibt lauffähig, bevor + # der Storage eingerichtet ist. Config-Werte brauchen die {"v":…}-Kodierung. + token = os.environ.get("GIT_STORAGE_TOKEN", "").strip() + repo = os.environ.get("GIT_STORAGE_REPO", "").strip() + user = os.environ.get("GIT_STORAGE_USER", "").strip() + if not (token and repo and user): + log("Git-Storage übersprungen (GIT_STORAGE_TOKEN/REPO/USER nicht gesetzt)") + return + cfg = { + "authType": "basic", "repoUrl": repo, + "branch": os.environ.get("GIT_STORAGE_BRANCH", "main"), + "basicUsername": user, "basicPassword": token, "verifySSL": True, + "defaultEmail": os.environ.get("GIT_STORAGE_EMAIL", "wiki@localhost"), + "defaultName": os.environ.get("GIT_STORAGE_NAME", "Wiki"), + "sshPrivateKeyMode": "path", "localRepoPath": "./data/repo", + "alwaysNamespace": False, "gitBinaryPath": "", + } + config = [{"key": k, "value": json.dumps({"v": v})} for k, v in cfg.items()] + target = {"isEnabled": True, "key": "git", "mode": "sync", + "syncInterval": "PT5M", "config": config} + r = gql('mutation($t:[StorageTargetInput]!){storage{updateTargets(targets:$t)' + '{responseResult{succeeded message}}}}', + jwt, {"t": [target]})["storage"]["updateTargets"]["responseResult"] + if not r["succeeded"]: + sys.exit(f"Git-Storage fehlgeschlagen: {r['message']}") + log(f"Git-Storage aktiviert (Gitea, sync): {repo}") + + def group_id(jwt: str, name: str): for g in gql("{groups{list{id name}}}", jwt)["groups"]["list"]: if g["name"] == name: @@ -248,6 +280,7 @@ def main(): ensure_oidc(jwt) set_hide_local(jwt) ensure_theming(jwt) + ensure_git_storage(jwt) log("fertig — Wiki.js konfiguriert") diff --git a/apps/production/wikijs-config.yaml b/apps/production/wikijs-config.yaml index 90f3cba..85a47f5 100644 --- a/apps/production/wikijs-config.yaml +++ b/apps/production/wikijs-config.yaml @@ -45,6 +45,25 @@ spec: secretKeyRef: name: wikijs-oidc-secret key: client_secret + # Git-Storage (ADR-0015): Inhalt nach Gitea syncen. Klartext-Koordinaten; + # nur der PAT liegt im SOPS-Secret wikijs-git-secret. optional=true, damit + # der Job auch läuft, bevor das Secret existiert (Skript überspringt dann). + - name: GIT_STORAGE_REPO + value: https://rohana.axion1337.de/sorb/ThreadNetWiki.git + - name: GIT_STORAGE_USER + value: sorb + - name: GIT_STORAGE_BRANCH + value: main + - name: GIT_STORAGE_EMAIL + value: wiki@axion1337.chat + - name: GIT_STORAGE_NAME + value: ThreadNet Wiki + - name: GIT_STORAGE_TOKEN + valueFrom: + secretKeyRef: + name: wikijs-git-secret + key: token + optional: true volumeMounts: - name: script mountPath: /script diff --git a/apps/production/wikijs-git-secret.yaml b/apps/production/wikijs-git-secret.yaml new file mode 100644 index 0000000..82360ee --- /dev/null +++ b/apps/production/wikijs-git-secret.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +data: + token: ENC[AES256_GCM,data:Z+oD7NDgHTTuMyNLFY+2PhZmTJzN4eIAGgmCx2TnI73BQ2v40Um/ppioLY4kyow56lfj23jpI6w=,iv:/Y7Oti9e7+Se4DjxI1nT4J0f+l73PKNbgbeSiyIpdU8=,tag:ilW/M/uSTn8qOUcUfOhtwA==,type:str] +kind: Secret +metadata: + name: wikijs-git-secret + namespace: matrix +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4c3pFV3gxeEgrVjkzVnZ3 + TkZHbThJV0dqY3BXanhtMExzUTV3aTdXTlVVCjQxZjN2cjRiMjQzTG1XM3JyVzZt + Si9GL1ZEVFArd2FxR3ltaDJhS21GeFkKLS0tIHhKVUtKaUlFOGRkOGJNUkR0Ymwy + dzREc0lNMlowMXdNa1I3ODhsN2k4WUkKFRTpU/cQq0+EcIldJn3/77P6HYaxH0uK + Xd6CT+WdX83vcmwX4d1Brh6y3GEX+cKeNAaxUL4raZdkjCOz0n8bnQ== + -----END AGE ENCRYPTED FILE----- + recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh + encrypted_regex: ^(data|stringData)$ + lastmodified: "2026-08-13T09:46:49Z" + mac: ENC[AES256_GCM,data:STpYfsCDwZA1OIZLfTrO3Ww6Nuo8h/lIufrnQj8yeeuYcT1vEev0Tr/c2+8fNRW4yLEfRkqNMhP4p6akh9G2BChQN4FnwuUqb9yA7s+una83IXmn4UOCvwchxhY2c95lLKMNr45f3fUx6bw4tlENRor3ZrF3+jvvbX7b6c1XlC8=,iv:LVZdHBWSbwUgc4/JQSbw6twIVsa6QdSzAW7LnQn81I0=,tag:tTfFxm1URN1U1bbOroKHUA==,type:str] + version: 3.13.3