601 Commits

Author SHA1 Message Date
Will Anderson 086a7b0bf0 add DocuSeal to GKE — manifests, Terraform, Argo CD app; update ci-base Dockerfile 2026-05-05 10:38:45 -05:00
Will Anderson 73b9095d83 migrate Terraform backend to GCS, remove dead Vault GCE nodes
Switch gcp/ backend from Cloudflare R2 (S3-compatible) to GCS — uses
Application Default Credentials automatically, no extra env vars needed.
State has been migrated to gs://neuron-785695-terraform-state/gcp/.

Remove GCE Vault node resources (vault-node-1/2/3) from vault-nodes.tf
and Terraform state. GKE Vault (Workload Identity + vault-unseal SA) has
been serving traffic since the NEG cutover; GCE nodes are confirmed dead.

Removed from state and config:
- google_compute_instance.vault_node (x3)
- google_compute_disk.vault_data (x3)
- google_compute_instance_group.vault (x3)
- google_compute_firewall.vault_iap_ssh / vault_raft / vault_api (GCE-targeted)
- google_storage_bucket_object.vault_startup
- google_storage_bucket_iam_member.vault_node_bucket_read
- google_project_iam_member.vault_node_{log_writer,metric_writer,compute_viewer}

Kept: KMS, vault-unseal SA, WI binding, NEG data sources, GKE firewall,
global LB (address, cert, backend service, url maps, proxies, fwd rules).
2026-05-05 10:38:22 -05:00
Will Anderson d54ec38a1c fix GCE runner: add build tools, libcurl, NOPASSWD sudo, Node.js 20 2026-05-05 10:27:45 -05:00
Will Anderson 422cca6962 scale gitea-runner to 0 while Autopilot DinD blocker is pending
Set replicas: 0 to prevent crash-loop restarts. The runner requires a Docker
daemon (even in host mode) which Autopilot won't provide. Scale to 1 when a
Standard node pool or external Docker TCP endpoint is available.
2026-05-05 10:22:21 -05:00
Will Anderson 9a368986b2 fix gitea-runner deployment for GKE Autopilot constraints
Switch to host-mode labels and document the DinD limitation: Autopilot's
Warden blocks privileged containers at the node level. Use internal Gitea
service URL (gitea.gitea.svc.cluster.local) to bypass Cloudflare Access.
Document three resolution paths (Standard node pool, Cloud Build, external
Docker TCP). GCE VM runner remains active in the interim.
2026-05-05 10:22:02 -05:00
Will Anderson c31edc8b83 deploy gitea CI runner to GKE as k8s pod
Replaces the GCE VM runner with a k8s Deployment in the ci namespace on
neuron-platform GKE. Uses Docker-in-Docker for build isolation since
Autopilot doesn't expose the node socket. Runner token pulled from Secret
Manager via ESO + Workload Identity.

- servers/gcp/k8s/gitea-runner/: namespace, serviceaccount, external-secrets,
  deployment manifests (ci namespace, dind sidecar, idempotent registration)
- servers/gcp/k8s/argocd-apps/gitea-runner-gke.yaml: Argo CD Application
- servers/gcp/gitea-runner.tf: gitea-runner-gke GCP SA with secretAccessor
  on gitea-runner-token, Workload Identity binding for ci/gitea-runner,
  artifactregistry.reader for pulling ci-base image
2026-05-05 10:16:49 -05:00
Will Anderson 4dc687f2ae Fix runner extra_hosts: inject gitea-proxy ClusterIP for build containers
Build containers run with network: host, so k8s DNS doesn't resolve.
Add extra_hosts entry pointing gitea-proxy.ci.svc.cluster.local to its
ClusterIP (10.43.88.7) in both the will-org and neuron-technologies runner
configs. Without this, actions/checkout fails because Gitea passes the
proxy hostname as GITHUB_SERVER_URL and the build container can't reach it.

Also update stale CF Access comments that no longer reflect the architecture.
2026-05-05 05:41:59 -05:00
Will Anderson c94721b70b Remove SSH insteadOf rewrite from git-ssh-init.sh
Gitea's SSH server is disabled (START_SSH_SERVER=false) so the
SSH URL rewrite breaks git HTTPS clones in build containers. HTTPS
git ops work directly from Legion host network — Cloudflare bypasses
CF Access for smart-HTTP and release asset paths.
2026-05-05 05:27:44 -05:00
Will Anderson a301302138 Route gitea-proxy directly to GKE LB IP, drop CF Access
CF Access was blocking /api/actions/* even with the correct service-token
headers — the gRPC Actions ping endpoint returns 403 through Cloudflare.
Direct connection to the GKE Network LB IP (34.31.145.131) bypasses CF
entirely. Verified /api/actions/ping returns 200 from the LB IP directly.
2026-05-05 05:12:48 -05:00
Will Anderson 3462ea37a4 Add ignoreDifferences for Deployment status in gitea-gke
Argo CD's bundled schema is missing terminatingReplicas from the
Deployment status spec, causing a ComparisonError on every sync.
Ignoring /status entirely is safe — Argo CD never manages status
fields; they're owned by kube-controller-manager.
2026-05-05 05:07:15 -05:00
Will Anderson 82e05429f1 Fix Argo CD child app repoURL: k3s Gitea → GKE Gitea
gitea-gke and vault-gke were pointing at the dead k3s-internal Gitea
(http://gitea.git.svc.cluster.local:3000). gke-apps already uses
https://git.neuralplatform.ai and syncs successfully — update child apps
to match. Once gke-apps picks this up, gitea-gke will sync the pending
GITEA__actions__ENABLED=true commit.
2026-05-05 05:04:01 -05:00
Will Anderson 686041946b Enable Gitea Actions (GITEA__actions__ENABLED=true) 2026-05-05 04:56:29 -05:00
Will Anderson 158689dd0e Roll runner pods to pick up updated GITEA_INSTANCE_URL 2026-05-05 04:45:38 -05:00
Will Anderson b5c7125c13 Roll gitea-proxy pod for SNI fix 2026-05-05 04:42:08 -05:00
Will Anderson 464b33a176 Fix nginx SNI for Cloudflare upstream TLS
Without proxy_ssl_server_name on, nginx connects to Cloudflare's IP
without SNI, triggering handshake_failure (alert 40). Cloudflare requires
SNI to route TLS to the correct origin.
2026-05-05 04:41:46 -05:00
Will Anderson cebaf44db3 Scale GKE Vault to 1 replica while raft standby deadlock is unresolved
Pods 1 and 2 can't unseal because port 8201 (cluster port) only opens
after barrier initialization, but the barrier key transfer requires 8201
to be reachable — deadlock. Running single-node on pod 0 so
vault.neuralplatform.ai reliably routes to the active, unsealed instance.
2026-05-05 04:37:20 -05:00
Will Anderson 939e66bfbb Route runner daemon through nginx CF Access proxy
act_runner cannot inject custom HTTP headers, so CF Access blocks its
unauthenticated calls to git.neuralplatform.ai. Add a gitea-proxy
deployment (nginx:alpine) in the ci namespace that injects the CF
Access service-token headers and proxies to https://git.neuralplatform.ai.

Both runner secrets now point GITEA_INSTANCE_URL at the in-cluster proxy
(http://gitea-proxy.ci.svc.cluster.local:3000). Build containers still
clone via SSH through git-ssh-init.sh — unaffected.
2026-05-05 04:17:52 -05:00
Will Anderson ae3257525e wire soul to web_demo_key for Anthropic API isolation 2026-05-05 04:09:41 -05:00
Will Anderson c2900400a4 ci: switch runner git clones from HTTPS+CF Access to SSH deploy key 2026-05-05 04:07:35 -05:00
Will Anderson 2e5655c583 vault: rolling restart to fix raft join; remove sealedok from readiness probe 2026-05-05 03:59:33 -05:00
Will Anderson 3f08c6dc01 fix(runner): bump config-version to trigger rollout with new Gitea URL 2026-05-05 03:48:15 -05:00
Will Anderson 01507ad8ae fix(runner): point GITEA_INSTANCE_URL at GKE Gitea public URL
Gitea moved to GKE. The old in-cluster URL
http://gitea.git.svc.cluster.local:3000 now has 0 pods behind it.
The runner daemon gets connection refused on every poll.

Switch both ExternalSecrets to https://git.neuralplatform.ai.
The public URL does not require CF Access tokens — the runner can
connect without them. CF_ACCESS_CLIENT_ID/SECRET remain for git
operations inside CI job containers (via BASH_ENV init script).
2026-05-05 03:39:17 -05:00
Will Anderson 479190ef47 migrate all Argo CD repo sources from Legion Gitea to GKE Gitea 2026-05-05 02:25:14 -05:00
Will Anderson 804060c958 fix vault raft join addresses for GKE StatefulSet naming 2026-05-04 23:56:10 -05:00
Will Anderson 872a834989 Cut over Vault and Gitea traffic from GCE/Legion to GKE
Vault:
- Annotate vault-helm-gke Service with cloud.google.com/neg exposed_ports
  to create container-native NEGs (k8s1-bfbeff02-vault-...) in 3 zones
- Add vault-api-from-lb-gke firewall rule allowing GCP health check ranges
  (130.211.0.0/22, 35.191.0.0/16) to reach GKE pod IPs on port 8200
- Replace GCE instance group backends in google_compute_backend_service.vault
  with GKE NEG backends (RATE balancing mode, 100 req/endpoint)
- GCP Global HTTPS LB frontend unchanged — DNS stays at 34.54.164.21
- vault.neuralplatform.ai now terminates at GKE pods (all 3 NEGs HEALTHY)

Gitea:
- Change GKE Gitea Service from ClusterIP to LoadBalancer (external IP: 34.31.145.131)
- Add Cloudflare DNS A record for git.neuralplatform.ai → 34.31.145.131 (proxied)
- Remove git.neuralplatform.ai route from Legion Cloudflare tunnel config
- Add Cloudflare config rule: flexible SSL for git.neuralplatform.ai
  (origin serves HTTP/3000, CF proxies HTTPS termination)
- Scale Legion Gitea deployment to 0 replicas (PVC preserved)
- git.neuralplatform.ai now serves from GKE Gitea pod
2026-05-04 23:46:20 -05:00
Will Anderson 010d81d6d9 fix(runner): correct Gitea ClusterIP and enable force_pull
extra_hosts had stale IP 10.43.1.53 (Gitea is now at 10.43.15.98).
force_pull: true ensures runners always use the latest ci-base image.
Applies to both gitea-runner and neuron-technologies-runner.
2026-05-04 23:32:09 -05:00
Will Anderson 1c99931de6 fix(vault-gke): switch vault-1/2 to standard-rwo storage class
SSD quota (SSD_TOTAL_GB) is exhausted at 500/500 GB. pd-ssd PVCs for vault-1
and vault-2 cannot provision. Switching to standard-rwo (pd-balanced) unblocks
the Vault HA cluster immediately.

Quota increase request submitted (Cloud Quotas preference API, preference ID
0aa576b1-5050-4fa7-911d-6f408230df7f, target 1000GB). Once approved, can
optionally migrate back to premium-rwo for all-SSD Vault storage.
2026-05-04 22:41:38 -05:00
Will Anderson 3d581368c3 fix(vault-gke): relax topology spread to ScheduleAnyway while SSD quota is exhausted
vault-1 and vault-2 are stuck Pending because GCE quota (SSD_TOTAL_GB 500/500)
prevents new nodes from provisioning. ScheduleAnyway lets them land in any zone
that has capacity while the quota increase request is pending.

Also adds ESO Workload Identity IAM bindings to Terraform state (previously applied
out-of-band via gcloud; now tracked in cloud-sql.tf).
2026-05-04 22:37:17 -05:00
Will Anderson 8592a1ed74 fix(gitea-gke): configure ESO SecretStore to use workload identity with gitea SA 2026-05-04 22:05:01 -05:00
Will Anderson 9252b069a2 fix(gitea-gke): update ESO API version from v1beta1 to v1 2026-05-04 22:00:21 -05:00
Will Anderson c4f7dcc185 fix(vault-gke): raise cpu request to 500m for GKE Autopilot anti-affinity minimum 2026-05-04 21:59:51 -05:00
Will Anderson b572f5720b infra: wire GKE cluster endpoint and fix gitea SA account_id
- Replace GKE_CLUSTER_ENDPOINT placeholder with real endpoint (34.63.89.52)
  in all three Argo CD Application manifests
- Fix gitea GCP SA account_id from 'gitea' (5 chars, too short) to 'gitea-gke'
  to satisfy GCP's 6-30 char constraint
- Update serviceaccount.yaml annotation to match new SA email (gitea-gke@...)
2026-05-04 21:56:06 -05:00
Will Anderson 4ef5e99f31 fix(ci-base): correct Gitea namespace in git insteadOf redirect
Gitea lives in the 'git' namespace on Legion k3s, not 'gitea'.
The system gitconfig redirect must use gitea.git.svc.cluster.local:3000.
Update when Gitea migrates to GKE (namespace will be 'gitea' there).
2026-05-04 20:42:27 -05:00
Will Anderson 9330107fcc migrate Vault and Gitea to GKE Autopilot cluster
Implements Option A: move Vault (3x GCE e2-small) and Gitea (Legion k8s)
onto a new GKE Autopilot cluster (neuron-platform, us-central1) managed
through Legion Argo CD.

Terraform (servers/gcp/):
- gke.tf: GKE Autopilot cluster, Workload Identity bindings for Vault (KMS)
  and Gitea (Cloud SQL)
- cloud-sql.tf: gitea database + user on neuron-prod-pg15, gitea GCP SA,
  gitea-database-url and gitea-db-password Secret Manager secrets
- vault-nodes.tf: PENDING DECOMMISSION comment with migration checklist

k8s manifests (servers/gcp/k8s/):
- vault/: namespace.yaml
- gitea/: namespace, serviceaccount (Workload Identity annotation), pvc (50Gi
  standard-rwo), deployment (Gitea + Cloud SQL Auth Proxy sidecar), service,
  configmap (custom CSS carried from Legion), external-secrets (GCP SM provider)
- argocd-apps/: vault-gke.yaml, vault-helm-gke.yaml (Helm chart, HA Raft 3
  replicas, GCP KMS auto-unseal, topologySpread across zones, 10Gi premium-rwo),
  gitea-gke.yaml — all target GKE_CLUSTER_ENDPOINT placeholder

Legion (servers/legion/):
- apps/gke-apps.yaml: App-of-Apps entry point on Legion Argo CD that syncs the
  GKE Application manifests
- k8s/gitea-runner/Dockerfile: add system-level git insteadOf so GKE CI runners
  resolve Gitea in-cluster without Cloudflare Access headers
2026-05-04 20:40:48 -05:00
Will Anderson b4b05bfe40 fix(ci): remove duplicate runner Deployment from apps/
The stale apps/gitea-runner.yaml contained two Deployment manifests
that conflicted with the canonical Deployments owned by the
gitea-runner-config Argo Application (pointing at k8s/gitea-runner/).

Dual ownership caused Argo CD to fight itself — restarting runner
pods mid-job and producing the "context canceled" failures on
neuron-technologies/dharma-el CI.

Canonical Deployments (config-version 2026-05-04-cf-access-public-url,
docker.sock, CF Access env, replicas=2 for nt-runner) live in
k8s/gitea-runner/deployment.yaml and are managed by gitea-runner-config.
2026-05-04 17:55:28 -05:00
Will Anderson 48106b27ec vault: cut over to GCE Raft HA cluster, retire nook.family media stack
- dns-neuralplatform.tf: add vault.neuralplatform.ai A record → 34.54.164.21 (GCP LB)
  DNS-only (not proxied) so GCP managed TLS cert can provision correctly
- main.tf: remove vault.neuralplatform.ai from Cloudflare tunnel ingress
  (now served directly via GCP Global HTTPS LB)
- main.tf: remove watch.nook.family, jellyfin.nook.family, bazarr.nook.family
  from tunnel ingress (nook.family media stack retired; infra is Neuron-focused)

GCE Vault cluster already initialized and running (3-node Raft, active since
2026-05-04T16:05). Secrets migrated 48/48 from k3s vault. ESO ClusterSecretStore
validated against new vault. k3s vault-0 is now superseded.
2026-05-04 16:40:03 -05:00
will.anderson 0006380c27 route runner build container clones via public URL with CF Access (#7) 2026-05-04 21:37:53 +00:00
will.anderson 7ab97eb88d add CF Access service token for Gitea Actions runner (#5) 2026-05-04 21:25:20 +00:00
will.anderson 23fc64e7b7 fix(neuron-prod): set neuron-marketing-hpa minReplicas to 1 (#8) 2026-05-04 21:21:16 +00:00
will.anderson a64860064b fix(neuron-prod): add allow-dharma-ingress NetworkPolicy (#6) 2026-05-04 21:16:01 +00:00
will.anderson cbb564ccf5 revert(ci): runner public URL — CF Access blocks registration (#4) 2026-05-04 21:05:29 +00:00
will.anderson be0508037a fix(dharma): drop letsencrypt certResolver from IngressRoute 2026-05-04 20:56:29 +00:00
will.anderson 6f5d041440 fix(ci): point Gitea Actions runners at public instance URL 2026-05-04 20:56:26 +00:00
Will Anderson 4754c69e01 fix: mount /var/run/docker.sock (Docker Engine) not containerd socket 2026-05-04 14:10:25 -05:00
Will Anderson 0444d265b9 fix: gitea runner docker_host path mismatch — use /var/run/docker.sock
The containerd socket is mounted from the host at /run/k3s/containerd/containerd.sock
to /var/run/docker.sock inside the container, but act_runner config was pointing to
the host path directly. Fixes CrashLoopBackOff on all runner pods.

Also codifies both deployments (will org + neuron-technologies org) as git-managed
manifests so Argo CD owns them going forward.
2026-05-04 13:44:46 -05:00
Will Anderson 84688aec9d restore Always pull policy for engram-server: registry image now works
The registry image now compiles with -rdynamic/-ldl so dlsym can find
handle_request at runtime. IfNotPresent workaround no longer needed.
2026-05-04 11:43:52 -05:00
Will Anderson 10c3af4afe fix engram-server: use IfNotPresent pull policy to use local k3s cache
The buildah-compiled image (imported directly into k3s) is the working
version. The registry image will catch up after the next CI build.
IfNotPresent ensures the locally-cached correct binary is used.
2026-05-04 11:42:10 -05:00
Will Anderson 283e335e0a deploy engram-server to neuron-prod: dharma storage backend
- Add engram-server Deployment, Service, PVC to neuron-prod
- engram-server is the graph memory substrate for DHARMA registry
- Add allow-engram-ingress NetworkPolicy (ingress from neuron-prod)
- ENGRAM_URL in Vault updated to http://engram-server.neuron-prod.svc.cluster.local:8742
- Image: registry.neuralplatform.ai/neuron-technologies/engram-server:latest
  compiled from foundation/engram dist/engram.c + el_runtime
2026-05-04 11:28:45 -05:00
Will Anderson f2f20c1f2c remove missing soma manifests from prod kustomization
Soma moved to GCP Cloud Run. The soma-*.yaml files were deleted but
the kustomization still referenced them, blocking all Argo CD syncs
for neuron-prod (including the new allow-daemon-ingress NetworkPolicy).
2026-05-04 11:11:18 -05:00
Will Anderson 44faf74b61 fix CI runner secrets: correct Gitea URL and use Vault-backed tokens
The ExternalSecret had a stale Gitea URL (192.168.8.148:30322 — old
local IP) and runner tokens were never populated in Vault. Update the
template URL to the cluster-internal Gitea service DNS, and store the
registration tokens in Vault at secret/gitea.runner_token.
2026-05-04 11:07:43 -05:00