feat(infra): forte-drop in-cluster postgres + nightly backup (prod) #17

Closed
jorgen.stensrud wants to merge 7 commits from feat/forte-drop-infra into main

Summary

In-cluster Postgres + nightly backups for forte-drop in upc-dev. PROD setup.

Reworked since first open: in-cluster MinIO dropped. Object storage now uses the
existing UpCloud Managed Object Storage drops bucket (durable, UpCloud-replicated).
Added a pg backup CronJob + PVC prune protection + restore runbook.

What changed

  • forte-drop-postgresql — Postgres 16 StatefulSet, 5Gi PVC on upcloud-block-storage-maxiops, POSTGRES_DB=drops, creds from forte-drop-pg-creds SealedSecret. No securityContext (postgres image needs root to chown a fresh PVC, then drops to its own user via gosu).
  • forte-drop-pg-backup CronJob — nightly 02:00 UTC: pg_dump | gzips3://drops/_pgbackups/ (collision-proof prefix), 30-day retention. initContainer (pg_dump) + container (mc upload) sharing emptyDir. Reuses forte-drop-secrets S3 creds.
  • PVC prune/delete protectionargocd.argoproj.io/sync-options: Prune=false,Delete=false on the volumeClaimTemplate.
  • RESTORE.md — backup/restore runbook + disaster-scenario table.
  • MinIO removedforte-drop-minio/ deleted; object storage is UpCloud-managed.
  • Namespace forte-drop created via CreateNamespace=true (owned explicitly by the apps overlay's namespace.yaml, see the forte-drop-apps PR).

Depends on

forte-drop-secrets Secret (S3 creds for the backup CronJob) — sealed in the forte-drop-apps PR. The CronJob's first run no-ops until that lands; self-heals.

Test plan

  • kubectl kustomize clean
  • codex review: no actionable findings
  • post-merge: kubectl -n forte-drop get pods → postgresql-0 Running
  • manual backup job → confirm dump in s3://drops/_pgbackups/

🤖 Generated with Claude Code

## Summary In-cluster Postgres + nightly backups for forte-drop in upc-dev. **PROD** setup. > **Reworked since first open**: in-cluster MinIO dropped. Object storage now uses the > existing **UpCloud Managed Object Storage** `drops` bucket (durable, UpCloud-replicated). > Added a pg backup CronJob + PVC prune protection + restore runbook. ## What changed - **`forte-drop-postgresql`** — Postgres 16 StatefulSet, 5Gi PVC on `upcloud-block-storage-maxiops`, `POSTGRES_DB=drops`, creds from `forte-drop-pg-creds` SealedSecret. No securityContext (postgres image needs root to chown a fresh PVC, then drops to its own user via gosu). - **`forte-drop-pg-backup` CronJob** — nightly 02:00 UTC: `pg_dump | gzip` → `s3://drops/_pgbackups/` (collision-proof prefix), 30-day retention. initContainer (pg_dump) + container (mc upload) sharing emptyDir. Reuses `forte-drop-secrets` S3 creds. - **PVC prune/delete protection** — `argocd.argoproj.io/sync-options: Prune=false,Delete=false` on the volumeClaimTemplate. - **RESTORE.md** — backup/restore runbook + disaster-scenario table. - **MinIO removed** — `forte-drop-minio/` deleted; object storage is UpCloud-managed. - Namespace `forte-drop` created via `CreateNamespace=true` (owned explicitly by the apps overlay's namespace.yaml, see the forte-drop-apps PR). ## Depends on `forte-drop-secrets` Secret (S3 creds for the backup CronJob) — sealed in the **forte-drop-apps** PR. The CronJob's first run no-ops until that lands; self-heals. ## Test plan - [x] `kubectl kustomize` clean - [x] codex review: no actionable findings - [ ] post-merge: `kubectl -n forte-drop get pods` → postgresql-0 Running - [ ] manual backup job → confirm dump in `s3://drops/_pgbackups/` 🤖 Generated with Claude Code
jorgen.stensrud added 1 commit 2026-05-28 12:34:13 +00:00
feat(infra): forte-drop postgres + minio for upc-dev
All checks were successful
AI Code Review / ai-review (pull_request) Successful in 34s
3ce93017f9
Two new ArgoCD Applications:
- forte-drop-postgresql: in-cluster Postgres 16 StatefulSet, 5Gi PVC,
  POSTGRES_DB=drops, creds from forte-drop-pg-creds SealedSecret.
- forte-drop-minio: in-cluster MinIO StatefulSet, 20Gi PVC, bootstrap
  Job creates the 'drops' bucket post-sync, creds from
  forte-drop-minio-creds SealedSecret.

Both live in namespace 'forte-drop'. Mirrors the Vaultwarden pattern.

Sealed secrets are added in a follow-up commit by the maintainer:
  kubeseal --fetch-cert > pub.pem
  kubeseal --cert pub.pem --format yaml < private/forte-drop-pg-creds.yaml > \
    infra/overlays/upc-dev/forte-drop-postgresql/resources/forte-drop-pg-creds-sealed.yaml
  kubeseal --cert pub.pem --format yaml < private/forte-drop-minio-creds.yaml > \
    infra/overlays/upc-dev/forte-drop-minio/resources/forte-drop-minio-creds-sealed.yaml
jorgen.stensrud added the ai-review label 2026-05-28 13:55:16 +00:00
gitea_admin reviewed 2026-05-28 13:55:32 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +20,4 @@
project: default
source:
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
Owner

SSH Git URL exposes the internal Git server hostname and port which may be considered sensitive infrastructure information.

#ai-review-inline

SSH Git URL exposes the internal Git server hostname and port which may be considered sensitive infrastructure information. #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:32 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +1,4 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- forte-drop-minio.yaml
Owner

The referenced resource file 'forte-drop-minio.yaml' should exist in the same directory for this Kustomization to work properly.

#ai-review-inline

The referenced resource file 'forte-drop-minio.yaml' should exist in the same directory for this Kustomization to work properly. #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:32 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +1,4 @@
apiVersion: kustomize.config.k8s.io/v1beta1
Owner

Missing namespace field in Kustomization which is required for proper resource scoping.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: upc-dev
resources:
- forte-drop-postgresql.yaml

#ai-review-inline

Missing namespace field in Kustomization which is required for proper resource scoping. ```suggestion apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: upc-dev resources: - forte-drop-postgresql.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:34 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +15,4 @@
project: default
source:
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
Owner

Using SSH Git URL may cause access issues in CI/CD pipelines; consider using HTTPS with token authentication.

    repoURL: https://git.forteapps.net/Forte/launchpad.git

#ai-review-inline

Using SSH Git URL may cause access issues in CI/CD pipelines; consider using HTTPS with token authentication. ```suggestion repoURL: https://git.forteapps.net/Forte/launchpad.git ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:34 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +15,4 @@
project: default
source:
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
Owner

Using SSH Git URL may cause access issues in CI/CD pipelines; consider using HTTPS with token authentication.

    repoURL: https://git.forteapps.net/Forte/launchpad.git

#ai-review-inline

Using SSH Git URL may cause access issues in CI/CD pipelines; consider using HTTPS with token authentication. ```suggestion repoURL: https://git.forteapps.net/Forte/launchpad.git ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:35 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +16,4 @@
source:
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
targetRevision: HEAD
Owner

Using HEAD as targetRevision can lead to unpredictable deployments; pin to a specific branch or tag.

    targetRevision: main

#ai-review-inline

Using HEAD as targetRevision can lead to unpredictable deployments; pin to a specific branch or tag. ```suggestion targetRevision: main ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
Owner

Remove the '# added' comment as it's not necessary for production code.

apiVersion: kustomize.config.k8s.io/v1beta1

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion apiVersion: kustomize.config.k8s.io/v1beta1 ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Owner

Remove the '# added' comment as it's not necessary for production code.

kind: Kustomization

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion kind: Kustomization ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
Owner

Remove the '# added' comment as it's not necessary for production code.

resources:

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion resources: ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- minio.yaml
Owner

Remove the '# added' comment as it's not necessary for production code.

- minio.yaml

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion - minio.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +2,4 @@
kind: Kustomization
resources:
- minio.yaml
- forte-drop-minio-creds-sealed.yaml
Owner

Remove the '# added' comment as it's not necessary for production code.

- forte-drop-minio-creds-sealed.yaml

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion - forte-drop-minio-creds-sealed.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:35 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
gitea_admin reviewed 2026-05-28 13:55:35 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +16,4 @@
source:
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
targetRevision: HEAD
Owner

Using HEAD as targetRevision can lead to unpredictable deployments; pin to a specific branch or tag.

    targetRevision: main

#ai-review-inline

Using HEAD as targetRevision can lead to unpredictable deployments; pin to a specific branch or tag. ```suggestion targetRevision: main ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
Owner

Remove the '# added' comment as it's not necessary for production code.

apiVersion: kustomize.config.k8s.io/v1beta1

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion apiVersion: kustomize.config.k8s.io/v1beta1 ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Owner

Remove the '# added' comment as it's not necessary for production code.

kind: Kustomization

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion kind: Kustomization ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
Owner

Remove the '# added' comment as it's not necessary for production code.

resources:

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion resources: ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- minio.yaml
Owner

Remove the '# added' comment as it's not necessary for production code.

- minio.yaml

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion - minio.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +2,4 @@
kind: Kustomization
resources:
- minio.yaml
- forte-drop-minio-creds-sealed.yaml
Owner

Remove the '# added' comment as it's not necessary for production code.

- forte-drop-minio-creds-sealed.yaml

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion - forte-drop-minio-creds-sealed.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:35 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +16,4 @@
source:
repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git
targetRevision: HEAD
Owner

Using HEAD as targetRevision can lead to unpredictable deployments; pin to a specific branch or tag.

    targetRevision: main

#ai-review-inline

Using HEAD as targetRevision can lead to unpredictable deployments; pin to a specific branch or tag. ```suggestion targetRevision: main ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
Owner

Remove the '# added' comment as it's not necessary for production code.

apiVersion: kustomize.config.k8s.io/v1beta1

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion apiVersion: kustomize.config.k8s.io/v1beta1 ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Owner

Remove the '# added' comment as it's not necessary for production code.

kind: Kustomization

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion kind: Kustomization ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
Owner

Remove the '# added' comment as it's not necessary for production code.

resources:

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion resources: ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- minio.yaml
Owner

Remove the '# added' comment as it's not necessary for production code.

- minio.yaml

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion - minio.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +2,4 @@
kind: Kustomization
resources:
- minio.yaml
- forte-drop-minio-creds-sealed.yaml
Owner

Remove the '# added' comment as it's not necessary for production code.

- forte-drop-minio-creds-sealed.yaml

#ai-review-inline

Remove the '# added' comment as it's not necessary for production code. ```suggestion - forte-drop-minio-creds-sealed.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:35 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
gitea_admin reviewed 2026-05-28 13:55:36 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +45,4 @@
spec:
containers:
- name: minio
image: quay.io/minio/minio:latest
Owner

Using ':latest' tag is discouraged as it can lead to unpredictable deployments; pin to a specific version.

        image: quay.io/minio/minio:RELEASE.2024-03-15T01-07-19Z

#ai-review-inline

Using ':latest' tag is discouraged as it can lead to unpredictable deployments; pin to a specific version. ```suggestion image: quay.io/minio/minio:RELEASE.2024-03-15T01-07-19Z ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +121,4 @@
restartPolicy: OnFailure
containers:
- name: mc
image: quay.io/minio/mc:latest
Owner

Using ':latest' tag is discouraged as it can lead to unpredictable deployments; pin to a specific version.

        image: quay.io/minio/mc:RELEASE.2024-03-15T01-07-19Z

#ai-review-inline

Using ':latest' tag is discouraged as it can lead to unpredictable deployments; pin to a specific version. ```suggestion image: quay.io/minio/mc:RELEASE.2024-03-15T01-07-19Z ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +137,4 @@
- sh
- -c
- |
set -e
Owner

Shell script should include 'set -uo pipefail' for better error handling and safer execution.

          set -euo pipefail

#ai-review-inline

Shell script should include 'set -uo pipefail' for better error handling and safer execution. ```suggestion set -euo pipefail ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:36 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +45,4 @@
spec:
containers:
- name: minio
image: quay.io/minio/minio:latest
Owner

Using ':latest' tag is discouraged as it can lead to unpredictable deployments; pin to a specific version.

        image: quay.io/minio/minio:RELEASE.2024-03-15T01-07-19Z

#ai-review-inline

Using ':latest' tag is discouraged as it can lead to unpredictable deployments; pin to a specific version. ```suggestion image: quay.io/minio/minio:RELEASE.2024-03-15T01-07-19Z ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +121,4 @@
restartPolicy: OnFailure
containers:
- name: mc
image: quay.io/minio/mc:latest
Owner

Using ':latest' tag is discouraged as it can lead to unpredictable deployments; pin to a specific version.

        image: quay.io/minio/mc:RELEASE.2024-03-15T01-07-19Z

#ai-review-inline

Using ':latest' tag is discouraged as it can lead to unpredictable deployments; pin to a specific version. ```suggestion image: quay.io/minio/mc:RELEASE.2024-03-15T01-07-19Z ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +137,4 @@
- sh
- -c
- |
set -e
Owner

Shell script should include 'set -uo pipefail' for better error handling and safer execution.

          set -euo pipefail

#ai-review-inline

Shell script should include 'set -uo pipefail' for better error handling and safer execution. ```suggestion set -euo pipefail ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:36 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
gitea_admin reviewed 2026-05-28 13:55:37 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +40,4 @@
app.kubernetes.io/instance: forte-drop
app.kubernetes.io/component: database
spec:
containers:
Owner

Container is missing securityContext which should be set for security best practices.

      containers:
      - name: postgresql
        securityContext:
          runAsNonRoot: true
          runAsUser: 999
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: false

#ai-review-inline

Container is missing securityContext which should be set for security best practices. ```suggestion containers: - name: postgresql securityContext: runAsNonRoot: true runAsUser: 999 allowPrivilegeEscalation: false readOnlyRootFilesystem: false ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:37 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +40,4 @@
app.kubernetes.io/instance: forte-drop
app.kubernetes.io/component: database
spec:
containers:
Owner

Container is missing securityContext which should be set for security best practices.

      containers:
      - name: postgresql
        securityContext:
          runAsNonRoot: true
          runAsUser: 999
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: false

#ai-review-inline

Container is missing securityContext which should be set for security best practices. ```suggestion containers: - name: postgresql securityContext: runAsNonRoot: true runAsUser: 999 allowPrivilegeEscalation: false readOnlyRootFilesystem: false ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:40 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

apiVersion: kustomize.config.k8s.io/v1beta1

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion apiVersion: kustomize.config.k8s.io/v1beta1 ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

kind: Kustomization

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion kind: Kustomization ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

resources:

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion resources: ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- postgresql.yaml
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

- postgresql.yaml

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion - postgresql.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +2,4 @@
kind: Kustomization
resources:
- postgresql.yaml
- forte-drop-pg-creds-sealed.yaml
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

- forte-drop-pg-creds-sealed.yaml

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion - forte-drop-pg-creds-sealed.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +42,4 @@
spec:
containers:
- name: postgresql
image: postgres:16-alpine
Owner

Container image should use a pinned digest or exact tag instead of 'postgres:16-alpine' for better security and reproducibility.

        image: postgres:16.1-alpine

#ai-review-inline

Container image should use a pinned digest or exact tag instead of 'postgres:16-alpine' for better security and reproducibility. ```suggestion image: postgres:16.1-alpine ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:40 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

apiVersion: kustomize.config.k8s.io/v1beta1

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion apiVersion: kustomize.config.k8s.io/v1beta1 ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

kind: Kustomization

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion kind: Kustomization ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

resources:

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion resources: ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- postgresql.yaml
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

- postgresql.yaml

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion - postgresql.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +2,4 @@
kind: Kustomization
resources:
- postgresql.yaml
- forte-drop-pg-creds-sealed.yaml
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

- forte-drop-pg-creds-sealed.yaml

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion - forte-drop-pg-creds-sealed.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +42,4 @@
spec:
containers:
- name: postgresql
image: postgres:16-alpine
Owner

Container image should use a pinned digest or exact tag instead of 'postgres:16-alpine' for better security and reproducibility.

        image: postgres:16.1-alpine

#ai-review-inline

Container image should use a pinned digest or exact tag instead of 'postgres:16-alpine' for better security and reproducibility. ```suggestion image: postgres:16.1-alpine ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
gitea_admin reviewed 2026-05-28 13:55:40 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
gitea_admin reviewed 2026-05-28 13:55:40 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
gitea_admin reviewed 2026-05-28 13:55:40 +00:00
gitea_admin left a comment
Owner

Inline review

Inline review
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

apiVersion: kustomize.config.k8s.io/v1beta1

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion apiVersion: kustomize.config.k8s.io/v1beta1 ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

kind: Kustomization

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion kind: Kustomization ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

resources:

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion resources: ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- postgresql.yaml
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

- postgresql.yaml

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion - postgresql.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +2,4 @@
kind: Kustomization
resources:
- postgresql.yaml
- forte-drop-pg-creds-sealed.yaml
Owner

Remove inline comment '# added' as it appears to be temporary diff annotation.

- forte-drop-pg-creds-sealed.yaml

#ai-review-inline

Remove inline comment '# added' as it appears to be temporary diff annotation. ```suggestion - forte-drop-pg-creds-sealed.yaml ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
@@ -0,0 +42,4 @@
spec:
containers:
- name: postgresql
image: postgres:16-alpine
Owner

Container image should use a pinned digest or exact tag instead of 'postgres:16-alpine' for better security and reproducibility.

        image: postgres:16.1-alpine

#ai-review-inline

Container image should use a pinned digest or exact tag instead of 'postgres:16-alpine' for better security and reproducibility. ```suggestion image: postgres:16.1-alpine ``` #ai-review-inline
jorgen.stensrud marked this conversation as resolved
Owner

This PR adds new ArgoCD applications to deploy PostgreSQL and MinIO services for a forte-drop application in the upc-dev environment.

What changed: Added ArgoCD application definitions and Kubernetes manifests for PostgreSQL database and MinIO object storage components of the forte-drop system.

Affected services/namespaces:

  • New namespace: forte-drop
  • Services: forte-drop-postgresql (PostgreSQL database), forte-drop-minio (MinIO object storage)
  • ArgoCD applications managed in argocd namespace

Infrastructure impact:

  • PostgreSQL: 1 replica StatefulSet with 100m-500m CPU, 256Mi-512Mi memory limits, 5Gi persistent storage
  • MinIO: 1 replica StatefulSet with 100m-500m CPU, 256Mi-1Gi memory limits, 20Gi persistent storage
  • Both use upcloud-block-storage-maxiops storage class
  • MinIO includes bootstrap job to create 'drops' bucket

Security notes: Both applications reference sealed secrets (forte-drop-pg-creds, forte-drop-minio-creds) for database and MinIO credentials - requires verification that these sealed secrets exist and contain proper credentials before deployment.

#ai-review-summary

This PR adds new ArgoCD applications to deploy PostgreSQL and MinIO services for a forte-drop application in the upc-dev environment. **What changed**: Added ArgoCD application definitions and Kubernetes manifests for PostgreSQL database and MinIO object storage components of the forte-drop system. **Affected services/namespaces**: - New namespace: forte-drop - Services: forte-drop-postgresql (PostgreSQL database), forte-drop-minio (MinIO object storage) - ArgoCD applications managed in argocd namespace **Infrastructure impact**: - PostgreSQL: 1 replica StatefulSet with 100m-500m CPU, 256Mi-512Mi memory limits, 5Gi persistent storage - MinIO: 1 replica StatefulSet with 100m-500m CPU, 256Mi-1Gi memory limits, 20Gi persistent storage - Both use upcloud-block-storage-maxiops storage class - MinIO includes bootstrap job to create 'drops' bucket **Security notes**: Both applications reference sealed secrets (forte-drop-pg-creds, forte-drop-minio-creds) for database and MinIO credentials - requires verification that these sealed secrets exist and contain proper credentials before deployment. #ai-review-summary
jorgen.stensrud added 1 commit 2026-05-28 13:56:26 +00:00
feat(infra): add forte-drop sealed secrets
All checks were successful
AI Code Review / ai-review (pull_request) Successful in 5s
416615a9e0
Pg and minio credentials sealed against upc-dev sealed-secrets-controller.
jorgen.stensrud requested review from danijel.simeunovic 2026-05-28 13:56:42 +00:00
jorgen.stensrud added 1 commit 2026-05-28 14:05:52 +00:00
fix(infra): pin minio/mc tags + add postgres securityContext + harden bootstrap script
All checks were successful
AI Code Review / ai-review (pull_request) Successful in 15s
69848e42f0
Address ai-review feedback on PR #17:
- Pin quay.io/minio/minio and mc to specific RELEASE tags (Renovate
  will bump). 'latest' is unpredictable in GitOps.
- Bootstrap script: set -e -> set -euo pipefail.
- Postgres container: runAsNonRoot, uid/gid 999, drop ALL caps,
  no privilege escalation. Matches PSS restricted profile.
Author
Member

ai-review triage

Gått igjennom alle 13 inline comments. Fixes pushet i 69848e4.

Accepted (4)

# Path Action
304a forte-drop-minio/resources/minio.yaml Pin quay.io/minio/minio:RELEASE.2024-12-18T13-15-44Z (was :latest) — Renovate vil bumpe
304c forte-drop-minio/resources/minio.yaml Pin quay.io/minio/mc:RELEASE.2024-11-21T17-21-54Z
304b forte-drop-minio/resources/minio.yaml bootstrap set -eset -euo pipefail
306 forte-drop-postgresql/resources/postgresql.yaml Add securityContext: runAsNonRoot, uid/gid 999, drop ALL caps, no priv escalation

Rejected (9 — false positives + convention)

  • 297, 300 — "SSH Git URL exposes internal hostname / use HTTPS instead": ssh://git@git.forteapps.net er konvensjonen brukt overalt i launchpad (sjekk Vaultwarden, Gitea, alle andre Applications). Konsistens > endring.
  • 298 — "Referenced resource file should exist": filen finnes; sannsynligvis halusinasjon fordi PR'en ble pushet i to commits.
  • 299 — "Missing namespace in Kustomization": namespace er satt per-resource i selve manifestene (postgresql.yaml + minio.yaml). Top-level Kustomization namespace ville overstyrt det.
  • 301 (×5), 307 (×5) — "Remove '# added' comment": de kommentarene finnes ikke i filene. Halusinasjon.
  • 307a — "Pin postgres:16-alpine to 16.1-alpine": 16-alpine følger major.minor floating som er fint for patch updates. Ekte pin = digest sha256; 16.1-alpine er ikke ekte pin (1 floater fortsatt). Renovate bumper når 16.2 kommer.

#sealed-secrets pushet tidligere (416615a). PR klar for re-review når du har tid @danijel.simeunovic

## ai-review triage Gått igjennom alle 13 inline comments. Fixes pushet i `69848e4`. ### Accepted (4) | # | Path | Action | |---|---|---| | 304a | `forte-drop-minio/resources/minio.yaml` | Pin `quay.io/minio/minio:RELEASE.2024-12-18T13-15-44Z` (was `:latest`) — Renovate vil bumpe | | 304c | `forte-drop-minio/resources/minio.yaml` | Pin `quay.io/minio/mc:RELEASE.2024-11-21T17-21-54Z` | | 304b | `forte-drop-minio/resources/minio.yaml` bootstrap | `set -e` → `set -euo pipefail` | | 306 | `forte-drop-postgresql/resources/postgresql.yaml` | Add securityContext: runAsNonRoot, uid/gid 999, drop ALL caps, no priv escalation | ### Rejected (9 — false positives + convention) - **297, 300** — "SSH Git URL exposes internal hostname / use HTTPS instead": ssh://git@git.forteapps.net er konvensjonen brukt overalt i launchpad (sjekk Vaultwarden, Gitea, alle andre Applications). Konsistens > endring. - **298** — "Referenced resource file should exist": filen finnes; sannsynligvis halusinasjon fordi PR'en ble pushet i to commits. - **299** — "Missing namespace in Kustomization": namespace er satt per-resource i selve manifestene (postgresql.yaml + minio.yaml). Top-level Kustomization namespace ville overstyrt det. - **301 (×5), 307 (×5)** — "Remove '# added' comment": de kommentarene finnes ikke i filene. Halusinasjon. - **307a** — "Pin postgres:16-alpine to 16.1-alpine": `16-alpine` følger major.minor floating som er fint for patch updates. Ekte pin = digest sha256; `16.1-alpine` er ikke ekte pin (1 floater fortsatt). Renovate bumper når 16.2 kommer. #sealed-secrets pushet tidligere (`416615a`). PR klar for re-review når du har tid @danijel.simeunovic
jorgen.stensrud added 1 commit 2026-05-28 14:13:11 +00:00
fix(infra): drop bad postgres securityContext + un-own shared namespace
All checks were successful
AI Code Review / ai-review (pull_request) Successful in 6s
47d1f1ec39
Address Codex review on PR #17:

[P1] Postgres official image's entrypoint requires root to chown a
fresh PVC, then drops to the postgres user via gosu. Forcing
runAsNonRoot+runAsUser=999 blocks the chown and initdb fails on a
fresh volume. Drop the securityContext; matches the existing
vaultwarden-postgresql pattern.

[P2] The forte-drop namespace was declared as a managed resource
in the postgres Application. Since minio lives in the same
namespace from a separate Application, an Argo prune of the pg
app would delete the namespace and cascade-delete minio. Remove
the Namespace resource; rely on syncOptions: CreateNamespace=true
on both apps (already set).
jorgen.stensrud added 1 commit 2026-05-28 14:13:32 +00:00
fix(infra): un-own forte-drop namespace from postgres app
All checks were successful
AI Code Review / ai-review (pull_request) Successful in 6s
178bf8cc78
Follow-up to 47d1f1e — the previous commit only updated postgres'
securityContext; this drops the explicit Namespace resource as the
Codex review flagged. Both apps still get the namespace created via
syncOptions: CreateNamespace=true.
Author
Member

Codex review pass (P1+P2)

Kjørte gpt-5 codex review etter ai-review fixes. To ekte regresjoner funnet og fikset:

P1 — postgres securityContext breaker initdb (47d1f1e)

Ai-review pushet runAsNonRoot: true, runAsUser: 999, runAsGroup: 999 på postgres-containeren. Postgres official image's entrypoint må starte som root for å chowne en fresh /var/lib/postgresql/data, så drops den selv til postgres user (uid 70 i alpine) via gosu. Forced UID 999 fra k8s blokkerer chown → initdb feiler på fresh PVC.

Fix: dropp securityContext. Matcher Vaultwarden-mønsteret. Bevisst valg dokumentert i kommentar over containeren.

P2 — Namespace ownership cascade-risk (178bf8c)

forte-drop-postgresql.yaml deklarerte Namespace/forte-drop som managed resource. MinIO bor i samme namespace fra en separat Application. Hvis postgres app prunes/slettes → Argo prunes namespace → MinIO cascade-deletes.

Fix: fjern Namespace resource fra postgres-applikasjonen. Begge apps har allerede syncOptions: CreateNamespace=true så ArgoCD lager namespacet ved første sync uten å eie det.

Klart for re-review @danijel.simeunovic

## Codex review pass (P1+P2) Kjørte gpt-5 codex review etter ai-review fixes. To ekte regresjoner funnet og fikset: ### P1 — postgres securityContext breaker initdb (`47d1f1e`) Ai-review pushet `runAsNonRoot: true, runAsUser: 999, runAsGroup: 999` på postgres-containeren. Postgres official image's entrypoint må starte som root for å chowne en fresh `/var/lib/postgresql/data`, så drops den selv til postgres user (uid 70 i alpine) via gosu. Forced UID 999 fra k8s blokkerer chown → initdb feiler på fresh PVC. Fix: dropp securityContext. Matcher Vaultwarden-mønsteret. Bevisst valg dokumentert i kommentar over containeren. ### P2 — Namespace ownership cascade-risk (`178bf8c`) `forte-drop-postgresql.yaml` deklarerte `Namespace/forte-drop` som managed resource. MinIO bor i samme namespace fra en separat Application. Hvis postgres app prunes/slettes → Argo prunes namespace → MinIO cascade-deletes. Fix: fjern Namespace resource fra postgres-applikasjonen. Begge apps har allerede `syncOptions: CreateNamespace=true` så ArgoCD lager namespacet ved første sync uten å eie det. Klart for re-review @danijel.simeunovic
Owner

Du trenger ikke bry deg med .pem filer når du bruker kubeseal.

Du kan gjøre det slik:

kubectl create secret generic forte-drop-pg-creds \
  -n forte-drop \
  --from-literal=root-user=forte-drop-minio \
  --from-literal=root-password=$(openssl rand -hex 16) \
  --dry-run=client -o yaml \
| kubeseal --format=yaml \
  > infra/overlays/upc-dev/forte-drop-postgresql/resources/forte-drop-pg-creds-sealed.yaml

.pem er praktisk hvis man ikke har tilgang til clusteret ved seal, men det har du jo.

Du trenger ikke bry deg med `.pem` filer når du bruker `kubeseal`. Du kan gjøre det slik: ``` kubectl create secret generic forte-drop-pg-creds \ -n forte-drop \ --from-literal=root-user=forte-drop-minio \ --from-literal=root-password=$(openssl rand -hex 16) \ --dry-run=client -o yaml \ | kubeseal --format=yaml \ > infra/overlays/upc-dev/forte-drop-postgresql/resources/forte-drop-pg-creds-sealed.yaml ``` `.pem` er praktisk hvis man ikke har tilgang til clusteret ved seal, men det har du jo.
Owner

Jeg vil foretrekke å ha denne deployment i apps, ikke infra. Det er bare en enkel flytt av alt, strukturen skal være samme.

Jeg vil foretrekke å ha denne deployment i `apps`, ikke `infra`. Det er bare en enkel flytt av alt, strukturen skal være samme.
jorgen.stensrud added 1 commit 2026-05-29 07:32:25 +00:00
feat(infra): drop in-cluster minio, add pg backup + PVC protection
All checks were successful
AI Code Review / ai-review (pull_request) Successful in 7s
dd9819bdbe
PROD: object storage moves to UpCloud Managed Object Storage (existing
drops bucket) instead of single-node in-cluster MinIO — durable,
UpCloud-replicated, no PVC to back up.

- Remove forte-drop-minio StatefulSet entirely.
- Add forte-drop-pg-backup CronJob: nightly pg_dump -> gzip -> upload to
  s3://drops/_pgbackups/ (collision-proof prefix), 30-day retention.
  Reuses forte-drop-secrets S3 creds (app user has s3:* on drops).
- PVC prune/delete protection on the postgres volumeClaimTemplate.
jorgen.stensrud added 1 commit 2026-05-29 08:31:11 +00:00
docs(infra): pg backup & restore runbook for forte-drop
All checks were successful
AI Code Review / ai-review (pull_request) Successful in 5s
94c7924e65
Covers: nightly backup mechanism, listing backups, manual trigger,
full restore procedure (2-pod mc-download + psql-pipe), verification,
object-data note, and a disaster-scenario recovery table.
jorgen.stensrud changed title from feat(infra): forte-drop postgres + minio for upc-dev to feat(infra): forte-drop in-cluster postgres + nightly backup (prod) 2026-05-29 08:32:34 +00:00
jorgen.stensrud removed review request for danijel.simeunovic 2026-05-29 08:32:52 +00:00
Author
Member

Takk! Begge tatt:

  1. kubeseal uten .pem — vi sealer allerede mot clusteret (--controller-name --controller-namespace), ingen .pem.
  2. Flytt til apps — gjort. Postgres + backup + creds ligger nå i apps/base/forte-drop-postgresql/ (samme struktur, bare flyttet). Hele forte-drop-deployen (postgres + web + mcp) er nå samlet under apps/ i #18.

Lukker denne — supersedet av #18.

Takk! Begge tatt: 1. **kubeseal uten .pem** — vi sealer allerede mot clusteret (`--controller-name --controller-namespace`), ingen .pem. 2. **Flytt til apps** — gjort. Postgres + backup + creds ligger nå i `apps/base/forte-drop-postgresql/` (samme struktur, bare flyttet). Hele forte-drop-deployen (postgres + web + mcp) er nå samlet under `apps/` i #18. Lukker denne — supersedet av #18.
jorgen.stensrud closed this pull request 2026-05-29 08:39:42 +00:00
All checks were successful
AI Code Review / ai-review (pull_request) Successful in 5s

Pull request closed

Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Forte/launchpad#17