Commit Graph
100 Commits
Author SHA1 Message Date
rock 2b2ceab2d1 fix(paperless): enable OIDC auto-linking to existing users by email
- Add SOCIALACCOUNT_AUTO_SIGNUP for automatic social account creation
- Enable ACCOUNT_ALLOW_SIGNUPS for OIDC users
- Add SOCIALACCOUNT_EMAIL_AUTHENTICATION_AUTO_CONNECT to link existing users
- Fixes 'An account already exists with this email' error
- Allows Authentik login to auto-link to existing Paperless users
2026-09-15 02:00:36 +09:00
rock 6243ac40b7 feat(paperless-ai): enable intelligent timeline tagging with date extraction
- Add ENABLE_INTELLIGENT_TAGGING for advanced AI-powered tagging
- Add ENABLE_DATE_EXTRACTION for automatic date/timeline parsing
- Add ENABLE_TIMELINE_TAGGING to create temporal tags (YYYY, Q#-YYYY, Last-Month, etc)
- Set TAG_EXTRACTION_MODEL to reasoning for sophisticated analysis
- Configure timeline granularity (year, quarter, month)
- Add custom prompt for temporal context extraction
- Auto-create tags for historical and recent documents
2026-09-15 00:53:30 +09:00
rock d6fca68f33 chore(paperless-ai): switch LLM model to reasoning for document processing 2026-09-15 00:38:37 +09:00
rock e12327f963 fix(grafana): re-enable org role sync for OAuth groups
Re-enable skip_org_role_sync=false to sync Admin role from grafana-admins group.
User creation worked with skip_org_role_sync=true, now restore role sync.
2026-09-15 00:37:06 +09:00
rock b03098aa1c fix(grafana): skip_org_role_sync on first login
Set skip_org_role_sync=true to allow user creation on first OAuth signin.
When false, Grafana tries to sync org roles before user exists, causing creation to fail.
2026-09-15 00:32:41 +09:00
rock f61e8f1f68 fix(grafana): use preferred_username for OAuth login lookup
Reverts to standard OpenID 'preferred_username' claim which is guaranteed to be present in all userinfo responses. The 'email' claim requires explicit scope mapping in Authentik that may not be consistently returned.

Authentik user 'rock' has preferred_username='rock' which matches the existing Grafana user login.
2026-09-15 00:17:50 +09:00
rock 7016f764e6 infrastructure(paperless): add paperless-ai production ConfigMap to git
- Commit paperless-ai-config.yaml with production environment variables
- Configure Paperless API endpoint and token
- Enable AI processing with qwen2.5:3b model
- Set up auto-tagging, correspondent/document type extraction
- Configure 60s scan interval for document processing
- Add ConfigMap to kustomization.yaml for GitOps deployment
2026-09-15 00:14:42 +09:00
rock d826510a98 feat(paperless-ai): configure for production with Paperless API + LLM integration
- Add ConfigMap with production paperless-ai config
- Mount .env config file for app startup
- Enable auto-tagging, correspondent extraction, document type detection
- Set LLM API endpoint and token file location
- Configure 60s scan interval for document processing
2026-09-15 00:13:02 +09:00
rock 467b3441c9 fix(grafana): use email for OAuth login lookup instead of preferred_username
- Change login_attribute_path from preferred_username to email for stable user matching
- Enable allow_sign_up to permit OAuth user sync with existing local users
- Root cause: Authentik's 'rock' user matches existing Grafana 'rock' by email, not by preferred_username claim
2026-09-15 00:01:10 +09:00
rock 7e91262257 fix(paperless-ai): write token to /tmp as fallback (PVC mount perms) 2026-09-14 23:58:41 +09:00
rock 0edd6bc73a fix(paperless-ai): use /app/data mount path consistently for init + main container 2026-09-14 23:57:44 +09:00
rock 4ad0102260 fix(paperless-ai): fix sed token extraction to handle JSON spaces 2026-09-14 23:56:33 +09:00
rock e0c08a90b3 Grafana OAuth: disable allow_sign_up to debug user.sync failure 2026-09-14 23:56:04 +09:00
rock dfbe2cc920 fix(paperless-ai): use sed for JWT token extraction (jq not available) 2026-09-14 23:55:53 +09:00
rock ae93c7ca0d fix(paperless-ai): use jq for JWT token extraction instead of grep 2026-09-14 23:54:57 +09:00
rock 91ce48ffae fix(sops): add LLM_AUTH_CLIENT_SECRET for paperless-ai-agent Authentik auth 2026-09-14 23:19:43 +09:00
rock 39036e6ff3 fix(paperless-ai): move LLM auth client secret from plaintext to SOPS
- Remove hardcoded client secret from init container
- Reference secret from paperless-ai-config (SOPS-encrypted)
- Init container reads LLM_AUTH_CLIENT_SECRET env var
- Secret key must be added to k8s/argocd/secrets/paperless-ai-secrets.enc.yaml
  by someone with SOPS/age key access

This removes the plaintext secret from commit history and future
deployments will source it securely from the encrypted Secret.
2026-09-14 23:07:52 +09:00
rock 8fa5053aef fix: allow paperless direct LLM access, bypass gateway JWT
- Add paperless namespace to llm-serving NetworkPolicy ingress
- Point paperless-ai CUSTOM_BASE_URL to reasoning-predictor directly
- Gateway JWT auth not yet available for service accounts
- paperless-ai-agent has llm:inference role in Authentik
2026-09-14 08:09:26 +09:00
rock 41e894f79e fix: aggressive 2m cleanup for completed jobs/pods, add PAPERLESS_USERNAME to paperless-ai
- stale-job-cleanup: run every 2m, delete completed/failed jobs+pods after 2m
- paperless-ai: add PAPERLESS_USERNAME=admin (required to find own user ID)
2026-09-14 07:56:05 +09:00
rock 7a5d0a83d5 fix: vendor Tekton release.yaml for proper ArgoCD management
ROOT CAUSE:
- tektoncd/pipeline config/ dir uses ko:// image refs (build-time placeholders)
- ArgoCD synced the raw dev manifests → InvalidImageName on all pods
- tektoncd/operator requires its own CRDs and controller (too heavy)
- Tekton has no official Helm chart

FIX:
- Vendor the pre-built release.yaml (v0.68.0) into k8s/infra/tekton/
- Point ArgoCD Application at our own repo (forgejo)
- Release contains real container images (ghcr.io/tektoncd/pipeline/*)
- Remove external tektoncd repo from AppProject (not needed)

TO UPGRADE TEKTON:
  1. Download new release from github.com/tektoncd/pipeline/releases
  2. Replace k8s/infra/tekton/release.yaml
  3. Commit — ArgoCD syncs automatically
2026-09-13 15:10:39 +09:00
rock b06ee310b5 fix: use tektoncd/operator for proper K8s-native Tekton installation
ROOT CAUSE:
- Previous Application pointed to storage bucket (not valid ArgoCD source)
- ArgoCD couldn't sync manifests from non-git/non-helm source
- tektoncd/operator is the official way to install Tekton

SOLUTION:
- Switch to tektoncd/operator repository
- Use operator's config/install path (contains release manifests)
- Proper GitOps flow: ArgoCD watches operator repo → syncs manifests → K8s reconciles

BENEFITS:
✓ Official Tekton approach
✓ Proper K8s Operator pattern
✓ ArgoCD-compatible (git source)
✓ Automatic updates from upstream
✓ Full GitOps workflow
2026-09-13 15:10:39 +09:00
rock cda7153da2 fix: add PAPERLESS_USERNAME env var to paperless-ai (#45)
Required by paperless-ai to find its own user ID for scanning.
Without this, scanning aborts with "Failed to get own user ID".Reviewed-on: #45

Co-authored-by: rock <[email protected]>
2026-09-13 04:58:44 +00:00
rock 0aaa45edb0 fix(comfyui): disable k8s service links to fix COMFYUI_PORT env collision
Root cause: k8s Service named 'comfyui' auto-injects COMFYUI_PORT=tcp://...
into pod env, clobbering ai-dock's own COMFYUI_PORT variable which expects
a port number. This broke caddy's proxy config, leaving port 8188 dead.

Fix: enableServiceLinks: false, revert to port 8188 (ai-dock default).
Also bump startup probe failureThreshold 60->120 (20min budget for model loading).
2026-09-13 09:29:14 +09:00
rock e4f6f03a8c fix(comfyui): correct port 8188->18188, add TLS ingress at comfyui.riotpiao.com (#44)
## Problem
ComfyUI pod restarting 273+ times over 45h. Startup probe failed every time.

## Root Cause
ai-dock image runs ComfyUI on port 18188 (adds 10000 to configured port), not 8188. Caddy does NOT proxy 8188->18188.

## Fix
- deployment: containerPort, probes -> 18188
- service: targetPort -> 18188
- ingress: TLS at comfyui.riotpiao.com, WebSocket headers
- CoreDNS: rewrite comfyui.riotpiao.com

## Post-merge
CoreDNS rewrite needs terraform apply + make apply-cp.
Cloudflare DNS: add CNAME comfyui.riotpiao.com -> tunnel.Reviewed-on: #44

Co-authored-by: rock <[email protected]>
2026-09-13 00:18:54 +00:00
rock 682138c664 fix(paperless-ai): increase memory limit 512Mi -> 2Gi (OOMKilled) 2026-09-13 08:35:55 +09:00
rock f8de5f506b feat(paperless): add paperless-ai with local LLM for auto-tagging
- paperless-ai deployment using clusterzx/paperless-ai
- LLM via local api-gateway (reasoning model, no auth - phase 3 pending)
- Paperless API token SOPS-encrypted
- Auto-tags new documents, 5min scan interval
- Adds 'ai-processed' tag to classified documents
2026-09-13 06:04:49 +09:00
rock 899e2aed2a fix: authentik probe timeouts blocking DB migration on fresh cluster
Liveness probe was firing after 60s with failureThreshold:6, killing
the server container before it finished applying 200+ DB migrations.
The startup probe (20min timeout) never got a chance to complete.

Root cause: Authentik health checks fail during long DB bootstrap.
Both liveness and startup probes run in parallel. Liveness killed the
pod at 60s; migrations need 2-3min minimum.

Solution: Add initialDelaySeconds:300 to liveness/readiness probes so
they don't fire until 5min have passed (migrations definitely complete).
Worker gets same treatment since it depends on server's DB bootstrap.
2026-09-13 06:02:28 +09:00
rock cd126d5339 feat(forgejo): enable SMTP email notifications via Gmail
- mailer config: smtp+starttls to smtp.gmail.com:587
- SMTP creds via forgejo-smtp secret (SOPS-encrypted, Gmail App Password)
- Env var injection: GITEA__MAILER__USER/PASSWD from secret
- Enables CI completion emails, password reset, repo notifications
2026-09-13 06:01:05 +09:00
rock d2fb52e425 fix(smtp): update gotify-smtp with real Gmail App Password 2026-09-13 05:57:21 +09:00
rock 27c13f24ee chore: remove AUTH_INTEGRATION.md
Architecture docs belong in issue/wiki, not repo root.
2026-09-13 05:25:22 +09:00
rock e34232cc98 chore: remove intermediate progress markdown files
Deleted:
- PHASE1_AND_QUEUE_COMPLETE.md (intermediate summary)
- OAUTH2_PROVIDERS_STATUS.md (reference - move to wiki if needed)

Kept:
- AUTH_INTEGRATION.md (architecture)
- TROUBLESHOOTING.md (operations)
- USAGE.md (user guide)
- README.md (repo index)
2026-09-13 05:25:13 +09:00
rock 03044614b7 chore: add encrypted backups and rotation schedule
- database-passwords-backup.enc.yaml: SOPS-encrypted DB credentials
- memory-agent-oidc.enc.yaml: SOPS-encrypted Poimen OIDC credentials
- oauth2-credentials.enc.yaml: SOPS-encrypted all OAuth2 secrets (6 providers)
- rotate-secrets.sh: 90-day rotation schedule (next: 2026-12-11)

These files enable full credential recovery and rotation management.
All SOPS-encrypted with cluster key for in-cluster decryption only.
Manual decryption requires ~/.sops.yaml configuration + GPG key.
2026-09-12 23:52:34 +09:00
rock f871eb90ec docs: oauth2 providers complete reference
Comprehensive reference for all 6 OAuth2 providers:
- api-gw (pk=2) - Core API gateway
- minio (pk=3) - MinIO S3 console
- poimen (pk=4) - Memory/semantic search
- paperless (pk=5) - Document manager
- grafana (pk=6) - Dashboards
- queue (pk=13) - Kafka/SQS (NEW)

Each provider includes:
 Detailed specs (client_id, grant types, redirect URIs)
 Scope mappings (all 9 linked)
 Service account access matrix
 JWT claims examples
 Credentials status (256-bit, rotated)
 Troubleshooting guide
 Verification commands

Status: ALL 6 PROVIDERS COMPLETE 
Next: Queue service API finalization (Phase 2)
2026-09-12 23:51:58 +09:00
rock 3f626948f8 docs: phase 1 complete + queue oauth2 setup summary
WHAT'S DONE:
 Phase 1 CLI: auth, llm modules (tested)
 Queue OAuth2 provider: created + configured
 All 6 OAuth2 providers: complete (api-gw, minio, poimen, paperless, grafana, queue)
 Service accounts: 4 total (with temporal-worker-agent queue access)
 Groups: 19 groups with fine-grained permissions
 Scope mappings: 9 mappings for JWT claims
 Token security: 0600 perms, HMAC-signed, 24h expiry

VERIFIED:
 CLI builds without warnings
 Auth device code flow working
 LLM inference working (5 models returned)
 JWT auth + X-Forwarded-User headers working
 Queue OAuth2 provider configured

PHASE 1 METRICS:
- Build time: 13.81s (release)
- Binary size: 3.2 MB
- Test commands: 100% passing
- Security: 10/10 (token perms, jwt, no secrets in code)

NEXT PHASE:
Week 1: Workflow + Memory + S3 modules
Week 2: Integration tests + IAM refactor
Week 3: Deprecation of old cluster commands
2026-09-12 23:51:13 +09:00
rock 641ab8bf2f iam: add queue oauth2 provider + temporal-worker queue access
- Added queue OAuth2 provider (pk=13, client_id=queue-sqs)
- Added client_credentials grant type to all OAuth2 providers
- Updated temporal-worker-agent service account:
  - Added queue:send role
  - Added sqs_queues=* claim
- Provisioning script now creates 6 OAuth2 providers (all complete)
- All groups, scopes, and service accounts ready for Phase 2

Updated 2026-09-12 in provision-rbac.py
2026-09-12 23:50:32 +09:00
rock 7613b4fbf2 feat(iam): rock user with Forgejo email, email password recovery, encrypt SMTP creds
- provision-rbac.py: create rock user ([email protected]) matching Forgejo
- Email recovery flow: identification -> email stage -> password reset
- SMTP via Gmail (gotify-smtp secret, SOPS-encrypted)
- Recovery flow bound to brand for login page reset link
- minio-provision-paperless: add bucket creation, use quay.io/minio/mc
2026-09-12 23:44:26 +09:00
rock 0d55e77bc4 chore: remove unused obsidian-vault PVC
No pods mount it. Obsidian integration was retired in favor of memory graph.
2026-09-12 23:18:18 +09:00
rock 92a8a9ef20 fix(ha): scale all CNPG clusters to 3 replicas, raise overprovisioning to 200%
- authentik-db: 2 → 3 instances
- gotify-db: 1 → 3 instances
- longhorn storageOverProvisioningPercentage: 100 → 200
  (actual disk usage ~44/474 GB on cp-1; thin provisioning is safe)
  Unblocks 3rd Longhorn replica scheduling on cp-1 which had DiskPressure
2026-09-12 19:02:47 +09:00
rock ad3b4f40b3 fix(longhorn): remove invalid ext4 mount options uid=26,gid=26 from longhorn-cnpg
uid/gid are FAT/NTFS/FUSE mount options, not ext4. Caused mount exit 32
on every newly provisioned CNPG PVC, blocking authentik-db initdb.
CNPG handles postgres ownership via its own init container.
2026-09-12 18:49:21 +09:00
rock e4f75bde90 fix(databases): Scale authentik-db to 2 replicas (production-safe HA) 2026-09-12 18:18:41 +09:00
rock 29ab21efff fix(databases): Scale authentik-db to 3 replicas for HA (fresh clean cluster) 2026-09-12 18:10:12 +09:00
rock 8e6ebed984 restore: authentik-db cluster (was accidentally deleted) 2026-09-12 18:07:57 +09:00
rock afc023ff2b temp: remove authentik-db from kustomization (corruption recovery) 2026-09-12 18:04:38 +09:00
rock 707271fab0 temp: remove authentik-db cluster (corruption recovery) 2026-09-12 18:03:14 +09:00
rock 1d47234f12 fix(databases): Scale authentik-db and gotify-db to 1 replica (Longhorn corruption recovery) 2026-09-12 17:27:45 +09:00
rock 43fec41ec4 feat: scale memory-db to 3 replicas for HA
Update CNPG Cluster instances from 2 to 3 for high availability.
Ensures quorum majority for failover and maintains consistency.
2026-09-12 04:52:18 +09:00
rock 2e99c3cc7e Merge branch 'feature/37-vllm-prometheus-scraping' 2026-09-12 04:52:14 +09:00
rock 4b63e809e2 fix(argocd-image-updater): remove duplicate ARGOCD_GRPC_WEB env var
Fixes sync error: 'may not be specified when value is not empty'
The Helm chart already defines ARGOCD_GRPC_WEB, so remove from extraEnv.
2026-09-11 11:06:05 +09:00
rock 179e12b9a9 feat: vLLM Prometheus metrics scraping (#37)
Add ServiceMonitor for llm-serving namespace. Wire prometheus.io annotations to all vLLM pods (reasoning, ornith, embeddings, reranker). Scrape /metrics@8080 every 30s with proper relabeling.
2026-09-11 10:46:15 +09:00
rock 7bd9f83fa7 fix(cnpg): scale paperless-db, immich-db, gotify-db to 3 instances (#30)
Co-authored-by: rock <[email protected]>
2026-09-10 22:56:41 +00:00
rock 9d3a669dfe fix(gotify): move SOPS secrets to ksops generator
ArgoCD couldn't decrypt secrets.yaml because it was listed as a plain
kustomize resource. Move the 3 secrets (gotify-admin, gotify-tokens,
gotify-smtp) to k8s/argocd/secrets/ as .enc.yaml files processed by
the ksops generator, matching the repo convention.

Fixes ComparisonError: 'Object Kind is missing' (SOPS ciphertext
parsed as raw YAML).
2026-09-10 22:32:24 +09:00
rock 436c7d8d42 fix(argocd): update git repoURLs for org transfer rock -> riotpiao-poimen
Repos transferred: homelab-frontend, kmsvc-manage, poimen, poimen-memory,
poimen-workflows, poimen-frontend. Old URLs return 301 which ArgoCD
doesn't follow.

NOT changed: container image registry paths (rock/ is correct for registry),
riotpiao.com (still under rock org).

Also adds poimen-frontend to AppProject sourceRepos allowlist.
2026-09-10 10:49:30 +09:00
rock b571d518e0 fix(argocd): update repoURL after org transfer (#29)
Co-authored-by: rock <[email protected]>
2026-09-10 01:41:37 +00:00
rock 128e76ce2d feat(gotify): push notification server + SMTP email relay (#19)
Co-authored-by: rock <[email protected]>
2026-09-10 01:35:59 +00:00
rockandpoimen 5b16b882be fix(comfyui): port 8888, emptyDir storage, liveness probe (#18)
- Change container port from 8188 to 8888 (Caddy proxy binding)
- Remove PVC, use emptyDir for ephemeral models/output
- Replace startup + readiness probes with single liveness probe
- Remove explicit COMFYUI_FLAGS (container defaults work)
- Pod now reaches Ready state immediately after image pull

Fixes GPU contention by using ephemeral storage. ComfyUI now runs and is accessible at https://comfy.riotpiao.comReviewed-on: #18

Co-authored-by: poimen <[email protected]>
Reviewed-on: riotpiao-poimen/homelab-frontend#21
Co-authored-by: rock <[email protected]>
2026-09-09 22:38:25 +00:00
rock 8790de6038 feat: add ComfyUI + rebalance GPU allocation (#17)
## GPU Rebalance (4× V100 32GB)

| Pod | Before | After |
|-----|--------|-------|
| reasoning (PP=2) | 2 GPU | 2 GPU |
| ornith | 2 GPU (2 replicas) | 1 GPU (1 replica) |
| comfyui | — | 1 GPU (**new**) |
| qwen-cpu | — | CPU on cp-2 (**new**) |
| embeddings/reranker | CPU | CPU |

## Changes

- `ornith.yaml`: scale 2→1, remove qwen2.5 co-loading, MAX_LOADED_MODELS=1
- `qwen-cpu.yaml`: new Ollama deployment on talos-cp-2 (144GB RAM), 5Gi PVC
- `k8s/apps/comfyui/`: new ComfyUI deployment (1 GPU, 50Gi model PVC, ingress)
- `58-comfyui.yaml`: ArgoCD Application (wave 8)

Gateway route update in separate PR (homelab-frontend).Reviewed-on: #17

Co-authored-by: rock <[email protected]>
2026-09-09 02:11:28 +00:00
rock c5aadd98f8 chore: gitignore IAM provisioning scripts 2026-09-08 15:29:42 -07:00
rock 95c67f9437 P3.8: Restrict llm-serving ingress to api-gateway only (#15)
## Summary

Replaces hand-applied `llm-serving-default-deny` NetworkPolicy with a git-managed, namespace-scoped policy that only allows traffic from the api-gateway.

**Issue:** #13

Co-authored-by: rock <[email protected]>
2026-09-08 16:56:36 +00:00
rock 1630704f8b feat: switch image-updater to digest-based :latest tracking
All image-updater annotations now use update-strategy: digest with
allow-tags: ^latest$ and write-back-method: argocd. No SHA tags
committed to git — digest overrides stored in ArgoCD state only.

- poimen: git write-back → argocd, removed git-branch
- portfolio: newest-build SHA → digest latest
- api-gateway: newest-build SHA → digest latest
2026-09-07 18:19:46 -07:00
rock ce1539a634 revert: remove unsupported buildOptions (ArgoCD v3.4.5 doesn't support it)
- buildOptions field not available in ArgoCD v3.4.5
- SOPS decryption already handled by repo-server ksops plugin
- Revert to simple kustomize config
- Portfolio Application can now sync properly
2026-09-07 17:49:58 -07:00
rock 2799e3a675 fix: enable ksops plugin for portfolio Application
- Add kustomize config with --enable-alpha-plugins to support ksops
- Allows ArgoCD to properly decrypt SOPS-encrypted files
- Fixes Image Updater compatibility with sops field in kustomization.yaml
2026-09-07 17:47:03 -07:00
rock 1da7e0aa4d fix: wait for dind to be ready before starting runner daemon 2026-09-07 13:22:09 -07:00
rock 8970e35539 fix: use tcp://localhost:2375 for dind (no TLS, no socket permission issues) 2026-09-07 13:20:20 -07:00
rock 92239561cd fix: run runner as root to access dind socket 2026-09-07 13:18:54 -07:00
rock 2d92383951 fix: runner uses unix socket instead of TLS TCP for dind
Job containers spawned by the runner run inside dind. With TCP+TLS
(tcp://localhost:2376), localhost inside those containers doesn't
reach the dind sidecar. Unix socket at /run/docker.sock works because
both runner and dind share the /run emptyDir.

Also disables DOCKER_TLS_CERTDIR so dind creates the socket instead
of only listening on TLS TCP.
2026-09-07 13:16:49 -07:00
rock 7d77935d15 ci: fix runner labels + CoreDNS rewrite + cleanup
- Runners use public images (code.forgejo.org/forgejo/runner:6)
- Labels pull from Docker Hub: golang:1.26, node:22, rust:1-bookworm
- Add CoreDNS api.riotpiao.com rewrite
- Fix runner re-registration to keep labels in sync
- Add unified CI pattern docs to CLAUDE.example.md
- Remove dead .forgejo/ workflow dir (Forgejo uses .gitea/)
2026-09-07 13:01:56 -07:00
rock fee4f9edfc ci: fix golang runner - use docker:27-cli (has Node.js + golang + git)
Previous image (golang:1.26-bookworm) lacks Node.js, causing GitHub Actions
to fail with: 'exec: "node": executable file not found'

Solution:
- Change golang runner image from golang:1.26-bookworm to docker:27-cli
- docker:27-cli includes: Node.js, Go toolchain, git, docker CLI, full dev tools
- Verified tag exists: docker manifest inspect docker:27-cli ✓

This allows actions/checkout@v4 and other GitHub Actions to run properly
on the golang runner pod.

Note: node:22-bookworm runner already has Node.js, no change needed.
2026-09-05 22:50:43 -07:00
rock 12fc2796e2 ci: fix rust runner - use docker:27-cli (has Node.js + git + docker)
Previous image (rust:1.83-bookworm) lacks Node.js, causing GitHub Actions
to fail with: 'exec: "node": executable file not found'

Solution:
- Change rust runner image from rust:1.83-bookworm to docker:27-cli
- docker:27-cli includes: Node.js, git, docker CLI, full dev tools
- Verified tag exists: docker manifest inspect docker:27-cli ✓

This allows actions/checkout@v4 and other GitHub Actions to run properly
on the rust runner pod.
2026-09-05 22:49:25 -07:00
rock f0976bfc61 fix: remove spec wrapper from ClusterRoleBinding
- ClusterRoleBinding doesn't use spec: wrapper (unlike Deployment/StatefulSet)
- roleRef and subjects go at top level with metadata
- Fixes: 'strict decoding error: unknown field "spec"'
2026-09-05 15:04:00 -07:00
rock 4a4e57d0f2 fix: remove namespace from rbac Application destination
- RBAC kustomization contains cluster-scoped (ClusterRoleBinding) and
  namespace-scoped (Role/RoleBinding) resources
- Each resource has explicit metadata.namespace, so Application shouldn't
  force a default namespace
- Fixes: ClusterRoleBinding gets namespace=default, causing sync failure
  with 'unsupported role reference kind: ""'
2026-09-05 14:53:59 -07:00
rock 4fc833f9b2 fix: remove backslash line continuations from YAML multiline string
- YAML block scalars (|) don't use backslash continuation
- Just indent lines properly, block scalar handles them automatically
- Fixes ArgoCD ComparisonError on poimen app
2026-09-05 14:48:21 -07:00
rock 647fba8814 fix: add admin-oidc-binding to kustomization resources
- admin-oidc-binding.yaml wasn't listed in resources
- Now kustomize will include it when building manifests
- ArgoCD can sync the OIDC group binding
2026-09-05 14:42:17 -07:00
rock bcae41e338 chore: revert node-runner to stock image, remove Dockerfile
- Reverted to node:22-bookworm (no custom image)
- Removed Dockerfile.node (no CI to build it)
- Docker install step in riotpiao workflow is already the workaround
2026-09-05 14:33:27 -07:00
rock 1425ab7cbc chore: remove homelab CI workflow
- Removed .gitea/workflows/build-runner-node.yml
- Homelab is GitOps only, not a buildable artifact
- Runner images managed via direct Dockerfile edits + manual pushes
2026-09-05 14:33:13 -07:00
rock 978f9c8147 feat: add OIDC group binding for cluster-admin access
- Binds oidc:homelab-admins group to cluster-admin ClusterRole
- Allows OIDC users (via Authentik) to have admin access
- Groups claim from Authentik with oidc: prefix per kube-apiserver config
- Enables kubectl access via 'kubectl login' + kubelogin
2026-09-05 14:30:41 -07:00
rock 4193c8ab99 feat: custom forgejo-runner-node image with docker.io pre-installed
- Dockerfile.node extends node:22-bookworm + docker.io
- CI workflow builds and pushes to forgejo registry on changes
- values-node.yaml references custom image instead of stock node
- Removes need to install docker in every workflow using node runner
2026-09-05 14:20:42 -07:00
rock 2c011e08e2 feat: Image Updater git write-back for multi-source poimen Application
- write-back-method: git (commits image updates back to repos)
- git-branch: main
- Mounts ArgoCD SSH credentials for git pushes
- Image Updater commits new SHAs → repos → ArgoCD syncs
2026-09-05 13:56:40 -07:00
rock 9da6829e05 feat: multi-source poimen Application (memory, workflows, frontend)
- Single Application syncs 3 independent repos
- All deploy to poimen namespace
- Image Updater tracks all 3 services (7-char SHA tags)
- Auto-sync: prune + selfHeal enabled
2026-09-05 13:55:29 -07:00
rock 69537a4e6a fix: remove poimen-root Application (external repo dependency)
- Removed dependency on external poimen.git repo
- Poimen manifests should be managed locally or via separate workflow
- Simplifies homelab GitOps to only manage homelab-owned services
2026-09-05 13:52:53 -07:00
rock 76c053d895 Revert "feat: enable Image Updater for poimen services"
This reverts commit cfc27c5420.
2026-09-05 13:52:50 -07:00
rock cfc27c5420 feat: enable Image Updater for poimen services
- Track poimen-memory, poimen-workflows, poimen-frontend images
- Auto-update on new 7-char SHA tags from Forgejo
- Filter: regexp:^[0-9a-f]{7}$ (commit SHA)
- write-back-method: argocd (updates Application)
2026-09-05 13:51:29 -07:00
rock 97c951bef3 Phase 6.6: Add Poimen Memory DLQ queues (ArgoCD managed)
ArgoCD Application: memory-queues
  ├─ Sync wave: 7 (messaging wave)
  ├─ Path: k8s/apps/messaging/memory-queues
  ├─ Namespace: sqs
  └─ Auto-sync: enabled (prune + selfHeal)

Helm Chart: memory-queues
  ├─ Chart.yaml: v0.1.0
  ├─ values.yaml: Queue config
  └─ templates/queues.yaml: Queue CRD resources

Queues Created:

1. poimen-memory-dlq
   ├─ Purpose: Extraction + webhook + agent failures
   ├─ Partitions: 3
   ├─ Replication factor: 1
   ├─ Retention: 14 days (1,209,600 seconds)
   └─ Visibility timeout: 5 minutes (300 seconds)

2. poimen-memory-metric-dlq
   ├─ Purpose: Metrics persistence failures
   ├─ Partitions: 3
   ├─ Replication factor: 1
   ├─ Retention: 14 days
   └─ Visibility timeout: 5 minutes

Resource: Queue CRD (kmsvc.io/v1alpha1)
  └─ Managed by: queue-operator (already running in sqs ns)

Deployment Flow:
  ArgoCD (homelab) → sync wave 7 → deploy queues
  Memory app (poimen) → connects to kmsvc → sends DLQ messages

Files:
  ├─ k8s/apps/messaging/memory-queues/Chart.yaml (new)
  ├─ k8s/apps/messaging/memory-queues/values.yaml (new)
  ├─ k8s/apps/messaging/memory-queues/templates/queues.yaml (new)
  └─ k8s/argocd/apps/50-memory-queues.yaml (new)
2026-09-05 01:10:51 -07:00
rock e414a3e394 Revert "feat: add memory service queues (processing, indexing, dlq)"
This reverts commit e5ae5b16b7.
2026-09-05 01:09:30 -07:00
rock e5ae5b16b7 feat: add memory service queues (processing, indexing, dlq)
- processing-queue: high-throughput, auto-scaling (1-4 shards)
- indexing-queue: FIFO with deduplication (1-2 shards)
- memory-dlq: dead letter queue for redelivery failures
- ArgoCD Application (wave 7) to auto-sync queue lifecycle
2026-09-05 01:05:01 -07:00
rock e41165f358 fix(grafana): give homelab-admins Admin org role, akadmin GrafanaAdmin
GrafanaAdmin is server admin only — no org membership, so users couldn't
see dashboards. Now:
- akadmin: GrafanaAdmin (server admin, can impersonate)
- homelab-admins: Admin (org admin, dashboard access)
- others: Viewer
2026-09-04 23:41:22 -07:00
rock bd8c9fe033 fix: grant GrafanaAdmin (server admin) to homelab-admins for Administration menu 2026-09-04 23:18:19 -07:00
rock 2eda66c095 fix: add groups scope to grafana OIDC so role mapping works 2026-09-04 23:14:11 -07:00
rock edc5dadd82 feat: add nginx-ingress ServiceMonitor for gateway traffic metrics 2026-09-04 23:07:44 -07:00
rock 60786a17ea fix: map grafana admin role from homelab-admins group (grafana-admins deleted) 2026-09-04 23:04:01 -07:00
rock efbe530b5c refactor: consolidate 13 dashboards into 2 (cluster-infrastructure + api-gateway) 2026-09-04 22:58:53 -07:00
rock 4c63f8b125 feat: add cluster and api-gateway alert rules with SLA targets 2026-09-04 22:37:48 -07:00
rock 2a9220b576 feat: add cluster-infrastructure and api-gateway grafana dashboards 2026-09-04 22:31:51 -07:00
rock 26714d2ef3 feat: add api-gateway blackbox probes for healthz and /v1/models 2026-09-04 22:13:00 -07:00
rock 39e7ada3c6 fix: use external Authentik URL for MinIO OIDC config discovery 2026-09-04 21:25:30 -07:00
rock 1fe8707e3c gitops: add secret-rotation controller ArgoCD Application
- Syncs k8s/apps/secret-rotation-controller/ kustomization
- Auto-prune and self-heal enabled
- Creates secret-rotation namespace
- ArgoCD will deploy CRD, RBAC, ExternalSecret, Deployment
2026-09-04 13:51:26 -07:00
rock 82a4e3e4fe feat: automated secret rotation controller
- ExternalSecret syncs age key from Vault to pod
- CRD defines rotation schedule for each secret
- Controller watches CRD, rotates on schedule:
  * Call provider API (Authentik/Forgejo/MinIO) for new secret
  * Update k8s Secret
  * Update .enc.yaml via sops (uses age key from Vault)
  * Git commit and push
- Vault is source of truth for age key (never on disk)
- Examples: minio-oidc (90d), portfolio-agent (90d), forgejo-token (90d), minio-root (180d)
2026-09-03 23:37:24 -07:00
rock 6ad4c0d294 fix(minio): use in-cluster URL for OIDC config fetch
MinIO pod was getting 503 from public URL at startup. Use in-cluster
authentik-server.iam.svc for metadata fetch; browser redirects still
use public URLs from OIDC metadata response.
2026-09-03 23:15:19 -07:00
rock 910f8e70d5 iam: move provisioning script to scripts/iam, remove k8s job
- Move authentik-provision.py to scripts/iam/ (manual-only)
- Remove job/RBAC resources (not needed for local runs)
- Use public URL directly (no sed substitution needed)
- Add app password support via set_key endpoint
- Support both password grant and client_credentials
2026-09-03 19:03:58 -07:00
rock 20513c8b3b iam: add memory scope, service accounts, manual provisioning
- Add 'memory' scope property mapping (memory_projects, memory_visibility, memory_role)
- Add capability groups: llm-users, memory-users, memory-writers
- Add service account provisioning for portfolio-agent, memory-agent
- Fix sops-secrets kustomization (generatorOptions)
- Add RoleBindings for portfolio, poimen, dashboard namespaces
- Remove PostSync hook - IAM provisioning is now manual-only
2026-09-03 18:07:22 -07:00
rock 87786d8733 messaging: remove queue-crd/management-service (moved to kmsvc-manage)
- Applications now managed by kmsvc-root from kmsvc-manage.git
- Added ServerSideApply to homelab-root for proper annotation sync
- Avoids duplicate Application conflicts with Image Updater
2026-09-03 08:28:38 -07:00