Commit graph

330 commits

Author SHA1 Message Date
dae6813386 imagePullPolicy: Always 2026-10-24 11:28:59 +02:00
221bd6b473 Merge branch 'main' of https://forgejo.basicstack.de/basicstack/stack.basicstack.de 2026-10-24 11:09:14 +02:00
b09fe3b23d imagePullPolicy: Always 2026-10-24 11:08:42 +02:00
CTO
ab60ef78f9 fix(argocd): bump application-controller memory 512Mi→1Gi (OOMKilled 1919× in 7d, DEV-596 preflight unblocker)
Container was repeatedly OOMKilled (exit 137) every ~5 s of live time since
2026-10-11 (pod age 6d23h, 1919 restarts). Live steady-state memory is now
~321 MiB with 1Gi/512Mi settings, so comfortable headroom. Patched the live
StatefulSet first to recover the control plane; this commit lets GitOps
retain the fix on the next reconcile.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-18 01:07:26 +00:00
CTO
a71c5d9a63 fix(opencloud): reduce CPU request 250m→50m to free worker-2 slot for backup CronJob (DEV-594)
Worker-2 CPU requests were pinned at 100% (2000m/2000m), leaving no room
for the daily opencloud-backup CronJob (needs 20m). Actual opencloud CPU
usage is ~3m — reserving 250m was 80x over actual. Reduce to 50m which is
still 15x headroom. Frees 200m on worker-2.

Backup CronJob is pinned to the opencloud node by RWO PVC + hard
podAffinity. Reducing opencloud's own CPU request is the cleanest
unblock — contained to the opencloud namespace, no cross-app blast
radius.

Related: DEV-593, DEV-464, DEV-481, DEV-514, DEV-582/584 (recurring
pattern of backup CronJob squeezed off worker-2).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-11 01:11:29 +00:00
5188784e86 apps/grist/grist-deployment.yaml aktualisiert 2026-09-27 09:55:23 +00:00
CTO
9305eb7415 fix(monitoring): Prometheus deployment source-of-truth + Recreate strategy (DEV-583)
Adds apps/monitoring/prometheus-deployment.yaml capturing the live PVC/Service/
Deployment for monitoring/prometheus. Two behaviour changes vs the previous
live state:

- strategy: RollingUpdate -> Recreate. prometheus-data-encrypted is RWO on
  hcloud-volumes-encrypted; a rolling update deadlocks because the surge pod
  cannot attach the PVC while the old pod holds it. This has been jamming the
  weekly OS-update preflight (see DEV-582). Same fix pattern as loki
  (loki-deployment.yaml) and opencloud (DEV-538).
- pod-template annotation backup.velero.io/backup-volumes-excludes:
  prometheus-storage. Restores the annotation that rev 6 tried to add before
  the RollingUpdate deadlock forced a rollback in DEV-582.

Applied and verified: rollout succeeded, /-/ready and /-/healthy both green,
pod running on k3s-worker-6 after PVC re-attach.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-13 01:11:07 +00:00
CTO (Paperclip Agent)
7368283d76 retire(monitoring): remove backup-k8s-resources CronJob + restic alerts (DEV-576)
Velero cluster-all now covers cluster-manifest backup with two successive
Completed runs verified and one restore drill (openwebui) green (DEV-575).

- Delete apps/monitoring/backup-k8s-resources-cronjob.yaml
- Drop BackupK8sResourcesStale + BackupK8sResourcesCheckFailed from
  backup-restic-alerts.yaml and matching series/cases from the promtool
  test file (all 9 remaining rules pass `promtool test rules`)
- Update apps/monitoring/README.md + prometheus-backup-cronjob comments
- Runbook lives in BookStack: EN
  https://books.basicstack.de/books/it-operations-manual/page/velero-backup-restore-runbook
  DE
  https://books.basicstack.de/books/it-betriebshandbuch/page/velero-backup-und-restore-runbook

Rollback: revert this commit — Argo restores the CronJob + alerts and
restic k8s-resources runs resume at the next 02:00 UTC schedule.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 18:24:07 +00:00
CTO (Paperclip Agent)
ac9f36b1e7 feat(velero): monthly restore-drill CronJob for openwebui (DEV-575)
- CronJob at 0 4 1 * * restores the latest openwebui-manifests backup into
  a transient restore-test-<ts> namespace, diffs core resource-kind counts
  against the live openwebui namespace, and deletes the target namespace.
- ServiceAccount + ClusterRole scoped to velero.io + namespace + configmap
  ops. Script enforces the 'restore-test-' name prefix before deleting a
  namespace. Cluster-wide 'view' bound for the diff.
- Failure surfaces via kube_job_status_failed (DEV-574 alert stack) and via
  ConfigMap velero-restore-drill-last-result written on every run.
- Optional Paperclip webhook Secret is sealed but unreachable from Hetzner
  right now (home Paperclip is LAN-only); wired as optional secretKeyRef so
  the drill runs regardless. Connectivity is a follow-up.
- Argo Application velero-restore-drill points at velero/restore-drill/.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 18:03:37 +00:00
CTO (Paperclip Agent)
6a66924595 feat(velero): ServiceMonitor + PrometheusRule for backup alerts (DEV-574)
Adds Prometheus scrape of Velero's :8085 metrics and four alerts
(VeleroBackupFailed, VeleroBackupPartial, VeleroBackupMissed,
VeleroStorageLocationUnavailable) labeled team=infra severity=warning.

VeleroStorageLocationUnavailable substitutes for the spec's
VeleroRepoUnhealthy since Velero v1.18.1 does not expose
velero_backup_repository_available (see comment in the rule).

Wired via a new ArgoCD Application (velero-monitoring) that syncs
only servicemonitor.yaml + prometheusrule.yaml from basicstack-repo/velero/.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 17:58:45 +00:00
CTO (Paperclip Agent)
ec3e9624b3 feat(velero): schedules + PVC exclude annotations (DEV-573)
- velero/schedules/: cluster-all @ 03:00 (30d TTL, manifests only),
  per-namespace <ns>-manifests @ 03:15+n min (30 in-scope namespaces,
  30d TTL, no fs backup), and per-namespace <ns>-data @ 03:45+n min
  for the whitelist (pocket-id, vaultwarden, vikunja, passbolt;
  14d TTL, defaultVolumesToFsBackup=true).
- All schedules exclude velero, kube-system, kube-node-lease,
  kube-public so the Kopia password Secret never lands in S3.
- apps/app-velero-schedules.yaml: sibling Argo app syncing that
  directory into namespace velero with prune+selfHeal.
- opencloud, harbor(registry+trivy): pod-template annotation
  backup.velero.io/backup-volumes-excludes as a safety net so blob-
  heavy PVCs are never fs-backed-up even under a manual defaultVolumes
  run. nextcloud/monitoring workloads are not Argo-tracked yet — they
  were patched live in the same commit but need a follow-up to source-
  control them.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 17:35:49 +00:00
CTO (Paperclip Agent)
9b8cfebbd5 velero: reseal S3 credential with new Hetzner project key
The prior sealed secret's access key lived in the personal `imicros.de`
Hetzner Object Storage project and could not list objects in
`basicstack-velero` (bucket is in the BasicStack project) — BSL was
`Unavailable` with an S3 `AccessDenied` on ListObjectsV2.

CEO created a new S3 credential in the BasicStack project; re-sealed
against the cluster controller and applied. BSL `default` now
`Available`.

Refs DEV-572.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 17:25:15 +00:00
CTO Agent
60cc931d6b fix(velero): pin AWS plugin to v1.14.2 (v1.14.3 unreleased); shrink node-agent memory req to fit workers (DEV-572)
- velero-plugin-for-aws v1.14.3 is not published on docker.io (only rc.1/rc.2). Downgrade to the latest GA tag v1.14.2 — still compatible with Velero 1.18.x.
- Drop node-agent memory request 256Mi -> 64Mi so the daemonset schedules on worker-1/2/3 (they sit at ~95% memory-request already).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 17:08:09 +00:00
CTO Agent
b3d98bf902 feat(velero): Argo app + Helm values for Kopia/Hetzner S3 backups (DEV-572)
- apps/app-velero.yaml: Argo Application, path apps/velero, ns velero,
  CreateNamespace + ServerSideApply (chart uses long CRDs).
- apps/velero/Chart.yaml: pinned vmware-tanzu velero chart 12.1.0
  (appVersion 1.18.1).
- apps/velero/values.yaml: Kopia uploader, no CSI, node-agent enabled,
  AWS S3 provider -> https://hel1.your-objectstorage.com, dedicated
  bucket basicstack-velero (per DEV-570), BSL credential
  velero-s3-credentials/cloud, Kopia repo password auto-picked from
  velero-repo-credentials/repository-password.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 17:05:42 +00:00
CTO Agent
f318719c59 velero(secrets): seal dedicated Hetzner OS S3 credential (DEV-570)
Adds SealedSecret velero-s3-credentials in namespace velero, holding
the dedicated velero-prod Hetzner Object Storage access/secret key
(scoped only to the basicstack-velero bucket).

Sealed on cp-1 via /root/seal-velero-s3-credentials.sh with the
sealed-secrets-controller public cert; plaintext never left the host.
Only the in-cluster controller can decrypt.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 17:00:43 +00:00
CTO Agent
0c82ded5f7 velero(secrets): seal Kopia repo password for velero namespace
Adds the SealedSecret for the Kopia repository password that the Velero
BackupRepository will consume once the Argo app lands. Raw password is
held on cp-1 (root:root, 0600) pending the CEO handoff to Vaultwarden
and the offline safe copy (DEV-571).

Refs: DEV-569, DEV-571

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 16:22:22 +00:00
CTO
b2ee3ffa67 feat(openwebui): deploy Open WebUI v0.11.3 with Pocket ID OIDC (DEV-567)
Adds the Open WebUI stack at openwebui.basicstack.de:

- Namespace `openwebui`, ArgoCD Application with auto-sync + selfHeal
- Own Postgres 16 + pgvector (`pgvector/pgvector:pg16`, 20Gi encrypted PVC,
  fsn1-pinned); VECTOR_DB=pgvector, extension auto-created
- Own Redis 7 (2Gi encrypted PVC, fsn1-pinned) used both as cache and as
  websocket manager (db=1)
- Hetzner Object Storage bucket `openwebui-basicstack` (hel1, path-style)
  for file uploads; shared project S3 credentials
- Traefik ingress + Let's Encrypt TLS
- Pocket ID client `Open WebUI` (PKCE on) restricted to groups
  `openwebui_admins` and `openwebui_users`; `andreas.leinen@basicstack.de`
  is member of both and gets admin via OAUTH_ADMIN_ROLES
- Password login disabled (`ENABLE_LOGIN_FORM=false`, `ENABLE_SIGNUP=false`)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-12 14:06:56 +00:00
CTO
b2b0d27803 fix(vikunja): set pod FQDN so SMTP EHLO passes Stalwart validation (DEV-563)
Stalwart's port-25 relay rejects bare EHLO labels — needs at least one
dot. Vikunja doesn't call go-mail's WithHELO, so it sends
os.Hostname() as EHLO. Setting hostname/subdomain plus
setHostnameAsFQDN=true makes the pod's kernel hostname a valid FQDN
(vikunja.basicstack.vikunja.svc.cluster.local), which Stalwart
accepts.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 10:05:26 +00:00
CTO
2ec560e090 feat(vikunja): enable mailer via port-25 in-cluster relay (DEV-563)
Vikunja now sends reminder/notification emails through
`stalwart-smtp.stalwart.svc.cluster.local:25` using unauthenticated
relay from the pod-network CIDR that Stalwart already trusts. The
`vikunja@basicstack.de` principal exists in Stalwart but its password
is unknown and admin API access to reset it is currently broken
(admin/andreas/paperclip password auth returns `{"type":"failure"}` per
`stalwart-oidc-only-admin` note). Verified end-to-end: message from
`vikunja@basicstack.de` sent via port-25 relay arrived in the passbolt
mailbox.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 10:03:07 +00:00
CTO
bf7e78a573 feat(kaneo): wire SMTP submission via kaneo@basicstack.de (DEV-562)
Adds the kaneo-smtp SealedSecret and points the Kaneo container at
mail.basicstack.de:587 (STARTTLS) for outbound workspace invites and
notifications. DISABLE_EMAIL_OTP_SIGN_IN stays true so sign-in remains
OIDC-only via Pocket ID.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 10:01:52 +00:00
CTO
2c9e90ac2b docs(outline): note PKCE must be disabled on the Pocket ID client
Outline's OIDC plugin does not send `code_challenge`, so the Pocket ID
client must be created with `pkceEnabled: false` (default is `true`).
Login fails with `?notice=auth-error` and Pocket ID rejects
`/authorize` when PKCE is enforced.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 09:57:39 +00:00
CTO
244ff86714 docs(vikunja): note PKCE must be off on Pocket ID client (DEV-560)
Vikunja 2.x's frontend redirect helper and Go backend do not send
code_challenge. Pocket ID rejects the /authorize call with
'code_challenge parameter is missing' when the client has pkceEnabled=true.
The Vikunja client is confidential (isPublic=false) so client_secret still
authenticates the token exchange — turning PKCE off is safe and required.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 09:56:07 +00:00
CTO
18eba97fcb feat(vikunja): request vikunja_scope for OIDC group→team mapping (DEV-564)
Add `vikunja_scope` to the OIDC scope list the Vikunja app requests
from Pocket ID, so the `vikunja_groups` custom claim is available for
Vikunja's automatic team provisioning.

The claim itself is set per Pocket ID user group (`vikunja_admins`,
`vikunja_members`) via `PUT /api/custom-claims/user-group/:id`.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 09:47:37 +00:00
cto-agent
38c7b8c624 feat(outline): deploy Outline knowledge base at outline.basicstack.de (DEV-559)
- Namespace `outline` with Postgres 16, Redis 7, and Outline 1.10.0
- Stateful pods pinned to Hetzner location `fsn1` (encrypted CSI volumes)
- Pocket ID OIDC integration (group-restricted to outline_admins/outline_members)
- Hetzner Object Storage bucket `outline-basicstack` (region hel1) with CORS
- Traefik Ingress with cert-manager `letsencrypt-prod` (DNS-01)
- Sealed secrets for postgres, app (SECRET_KEY/UTILS_SECRET/URLs), OIDC, S3
- Argo CD Application `outline` in `apps/app-outline.yaml`

SMTP notifications deferred (see apps/outline/README.md).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 09:42:21 +00:00
CTO
c184eeaff3 chore(vikunja): rename JWT env to non-deprecated service.secret (DEV-560)
Vikunja 2.6.0 deprecates `service.jwtsecret` in favor of `service.secret`;
switch the env var name (secret payload unchanged) and fix the admin-promotion
example in the README to the current CLI (`user set-admin --admin`).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 09:41:05 +00:00
CTO
1743815703 feat(vikunja): deploy Vikunja 2.6.0 with Pocket ID OIDC (DEV-560)
Namespace-scoped Postgres 16 + unified Vikunja container behind Traefik
ingress at vikunja.basicstack.de. Both pods pinned to Hetzner fsn1 due to
their encrypted PVCs (10 Gi DB, 10 Gi attachments). Local auth disabled;
sign-in only via Pocket ID (client `Vikunja`, groups `vikunja_admins` /
`vikunja_members`). SMTP mailer left disabled pending mailbox provisioning.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 09:38:25 +00:00
CTO
28a28bf7c0 feat(kaneo): deploy Kaneo project management (DEV-561)
Hand-rolled manifests under apps/kaneo/ + Argo Application:

- Dedicated PostgreSQL 16-alpine on hcloud-volumes-encrypted (20Gi),
  pinned to fsn1 via csi.hetzner.cloud/location node affinity.
- Kaneo v2.22.0 (single ghcr.io/usekaneo/kaneo image; API + web on
  5173). Pinned to fsn1 for consistency with the volume.
- Traefik ingress at kaneo.basicstack.de with letsencrypt-prod cert.
- Better Auth JWT secret and Postgres credentials as SealedSecrets.
- OIDC via Pocket ID using CUSTOM_OAUTH_*, restricted to the two
  new Pocket ID groups kaneo-admins / kaneo-members (client id
  d58ff9bb-dc98-49b4-9535-4af2aba66de2).
- Registration + password + email-OTP sign-in disabled; SSO only.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-05 09:38:04 +00:00
dda91a7471 apps/grist/grist-deployment.yaml aktualisiert 2026-08-30 12:03:03 +00:00
CTO
f29e2a5cb5 chore(grist): enable ArgoCD auto-sync + selfHeal (DEV-556)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-30 11:07:29 +00:00
CTO
8cdfd0e2f9 feat(grist): deploy Grist community edition (DEV-556)
- New namespace grist with in-namespace PostgreSQL 16
- Ingress grist.basicstack.de + letsencrypt-prod (DNS-01 via Hetzner)
- Pocket ID OIDC login (client "Grist", group "grist")
- All PVCs on hcloud-volumes-encrypted
- ArgoCD application via apps/app-grist.yaml

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-30 11:05:20 +00:00
CTO Agent
a61f0cd630 fix(opencloud): shrink backup pod requests to fit worker-3 (DEV-555)
The scheduled backup pod could not start because worker-3 (where the
opencloud data PVC is attached and where podAffinity pins the backup)
had ~40Mi of memory left by requests after opencloud/tika were
co-scheduled. rclone actually uses well under 100Mi during the sync.

Drop cpu request 100m -> 50m and memory request 256Mi -> 64Mi. Limits
unchanged (500m / 512Mi) so it can still burst.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-30 10:26:13 +00:00
CTO
c97a2d218e chore(stalwart): bump v0.16.11 -> v0.16.18 (DEV-542)
Transport-only patch bump. No auth/OIDC/config changes.
Snapshots (config.json, DB dump, live YAML) attached to DEV-542.
Rollback: git revert; ArgoCD resyncs; PVCs retained.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 16:46:31 +00:00
CTO
e69e3d8eb4 chore(restic): bump image 0.17.3 -> 0.19.1 (DEV-541)
Mirrored docker.io/restic/restic:0.19.1 to
harbor.basicstack.de/library/restic:0.19.1 (crane in-cluster Job).
Updated all CronJob pins and the restore-drill/tag-bump docs.

Digest: sha256:136600b6ff6843d61d355f7f71f460a166429f35de6fd11b568fece3c9a4d510

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:52:15 +00:00
CTO Agent
96c3846202 chore(stalwart): bump alpine 3.19 -> 3.24 in backup cronjob (DEV-539)
Only occurrence of plain alpine:3.19 across apps/**. Touches:
- apps/stalwart/stalwart-fresh-deployment.yaml (stalwart-backup CronJob container)

Scope excludes alpine/k8s (see DEV-520 majors phase).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:42:36 +00:00
CTO Agent
76e250c334 fix(opencloud): use Recreate rollout strategy for RWO PVC (DEV-538)
The 7.2.0 -> 7.4.0 rollout stalled because the default RollingUpdate
tried to start the new pod before terminating the old one, but they
both mount opencloud-data (RWO), causing Multi-Attach errors.

Switch to strategy: Recreate so the old pod is terminated first and
the volume detaches cleanly before the new pod starts. Same fix
pattern as bookstack (DEV-528) and other RWO-backed apps.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:39:17 +00:00
CTO Agent
0887f87c82 chore(opencloud): bump 7.2.0 -> 7.4.0 (DEV-538)
Skimmed 7.3.0 (2026-07-14) and 7.4.0 (2026-08-03) release notes: no
breaking changes, no config or index migrations required.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:35:03 +00:00
CTO
a7e81db4e1 chore(directus): bump 12.1.1 -> 12.3.0 (DEV-537)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:27:14 +00:00
CTO
777a4d0404 chore(pocket-id): bump v2.11.0 -> v2.14.0 (DEV-536)
Minor version bump of the cluster OIDC provider. No breaking changes;
multi-client-secret support in 2.14 is additive; SameSite=Lax cookie
default in 2.13 is standard. DB snapshot captured pre-rollout.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:18:23 +00:00
CTO
3317401eba chore(headlamp): bump v0.43.0 -> v0.45.0 (DEV-535)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:14:38 +00:00
CTO Agent
71496fc5ac chore(dozzle): bump v10.6.10 -> v10.7.3 (DEV-534)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:11:47 +00:00
CTO Agent
6313b85999 chore(pangolin): bump postgres 17.5 -> 17.11 (DEV-533)
Patch bump per DEV-520 plan. Only pangolin uses postgres:17.5*;
other apps (paperclip, directus, forgejo, stalwart) are on
postgres:16-alpine and are out of scope for this ticket.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:07:38 +00:00
CTO Agent
7cbb603ec1 chore(pangolin): bump busybox 1.37 -> 1.38.0 (DEV-532)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 15:02:26 +00:00
CTO Agent
a226958b16 chore(paperclip): bump busybox 1.36 -> 1.38.0 (DEV-531)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 14:59:34 +00:00
CTO Agent
e6a94ae26a chore(stalwart): remove no-op stalwart-allow-cluster-ips job (DEV-530)
The Job self-deletes after ttlSecondsAfterFinished=3600, causing ArgoCD
to report the app permanently OutOfSync. The job body only hits
/healthz/live and prints a manual TODO; it never modified Stalwart
config. The real IP allowlist is already declared in
apps/stalwart/stalwart-config.yaml under
[server.listener.*.security] allowed-ips.

Also removes the orphan ServiceAccount/Role/RoleBinding
stalwart-config-access bundled in the same file.

Board approval: DEV-529 interaction 9472bc9b-93d7-44e2-b32b-cf5598480f9a.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 14:18:26 +00:00
cto-agent
e155ab6a17 fix(bookstack): use Recreate rollout strategy (DEV-528)
BookStack is a single-replica Deployment backed by a ReadWriteOnce
PVC (`bookstack-config`). The default RollingUpdate strategy creates
the new pod before terminating the old one, and the two pods cannot
share the RWO volume — so every rollout deadlocks on
`Multi-Attach error for volume`.

Switching to `strategy: Recreate` terminates the old pod first,
releases the PVC, and then starts the new pod. Brief downtime is
expected on rollout, but rollouts actually complete.

Discovered while rolling out the `/status` probe fix (previous commit).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 12:01:35 +00:00
cto-agent
8a80068b95 fix(bookstack): point probes at /status instead of / (DEV-528)
BookStack's `/` returns 302 → /login, which caused Kubernetes to
raise ProbeWarning events on the readiness (and liveness) probes.
`/status` is BookStack's built-in monitoring endpoint: it returns
200 without a redirect and is designed for health checks.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 11:56:37 +00:00
CTO Agent
f5a0982222 fix(argocd): label argocd-oidc-secret so Argo CD reads its keys (DEV-523)
Argo CD only substitutes $secret:key references from Secrets carrying
the label app.kubernetes.io/part-of: argocd. Without it, the server
logs "secret key does not exist in secret" and renders placeholders
verbatim into the OIDC redirect URL.

Adding the label to the SealedSecret template ensures sealed-secrets-
controller re-produces the Secret with the label on every restore, so
OIDC keeps working after DR / re-seal.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 10:37:01 +00:00
CTO Agent
d1641c9047 fix(argocd): reference argocd-oidc-secret directly for OIDC (DEV-523)
Post-migration verify uncovered that Pocket ID OIDC login was broken:
the argocd-server was rendering $oidc.pocketid.clientId literally into
the authorize URL instead of substituting the client id.

The Helm chart's default $key syntax looks in argocd-secret, but our
OIDC keys are held only in the SealedSecret-backed argocd-oidc-secret
Opaque secret. Pre-migration argocd-secret happened to contain byte-for-
byte copies of those keys (legacy install), which is why it worked.

Switch to Argo CD's $secret:key form so the values point at the correct
secret without duplicating sealed material into argocd-secret.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 10:33:50 +00:00
CTO Agent
e8ab9d4674 fix(argocd): server.insecure=true for TLS-terminating ingress (DEV-522)
Argo CD server was returning HTTP 307 redirect loop behind Traefik
because it was serving HTTPS on port 8080 while the ingress terminates
TLS. Setting server.insecure so the server speaks plain HTTP internally.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 10:20:55 +00:00
CTO Agent
447ff93ccf fix(argocd): add forgejo internal SSH host key to values (DEV-522)
Argo CD repo-server needs the forgejo.forgejo.svc.cluster.local host key
in its known_hosts to clone the git repos over SSH. Adding it to
configs.ssh.extraHosts so the helm-managed ssh-known-hosts-cm renders
the entry from git and does not drift when the argocd Application syncs.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-23 10:18:04 +00:00