1 Commits

Author SHA1 Message Date
Will Anderson 24c2b056ab dharma: pin deployment image to SHA tag (placeholder)
Replaces `:latest` + `imagePullPolicy: Always` with a content-
addressable SHA tag produced by the dharma-el ci-prod workflow. The
deployed image is now deterministic and rollback is `git revert` of
this file.

`PINNED_BY_NEXT_BUILD` is a deliberate placeholder — Argo CD will fail
to reconcile (ImagePullBackOff) until a human replaces it with a real
short SHA. That failure is the forcing function: prod only gets a new
image via a PR that names a real, built tag.

This PR is opened as a draft. Do not merge until:
  1. dharma-el#1 (feature/ci-prod-image-build) is merged
  2. Dharma CI — prod runs on main and produces a SHA-tagged image
  3. The placeholder here is replaced with that SHA

`imagePullPolicy: Always` is left in place for now — redundant once
we're on SHA tags but removing it in the same PR adds risk. Drop it
in a follow-up.
2026-05-04 15:26:36 -05:00
4 changed files with 20 additions and 54 deletions
-42
View File
@@ -1,42 +0,0 @@
# Cloudflare Zero Trust Access — git.neuralplatform.ai (Gitea)
#
# The Gitea Access application itself is currently managed in the Cloudflare
# dashboard, NOT in Terraform. This file only manages the *service token* the
# Gitea Actions runners use to authenticate through CF Access while still
# keeping the human Google-OAuth gate for browser users.
#
# Why not import the application here?
# - Importing the existing dashboard app risks drifting the human-auth
# policy (Google IdP, allowed emails) which is settled and working.
# - Service tokens can be added to a dashboard-managed app without
# importing the app itself; the token resource lives at the account
# level and is referenced from a policy.
# - We pay only the cost we need to. If we later want all Access apps
# in TF we can do a focused import pass.
#
# After `terraform apply` produces the token id/secret, Will must:
# 1. Run `vault kv put secret/gitea-runner-cf-access ...` (see outputs).
# 2. In the Cloudflare dashboard, edit the existing "Gitea" Access
# application's policies and add a new policy:
# Action: Service Auth (decision = non_identity)
# Include: Service Token = "gitea-runner"
# This grants the service token bypass through CF Access on
# git.neuralplatform.ai without changing the human-auth flow.
resource "cloudflare_zero_trust_access_service_token" "gitea_runner" {
account_id = var.cloudflare_account_id
name = "gitea-runner"
# Default duration is "8760h" (1 year). Rotate via re-apply when needed.
duration = "forever"
}
output "gitea_runner_cf_access_client_id" {
description = "CF Access service token client ID for the Gitea Actions runner. Store in Vault at secret/gitea-runner-cf-access."
value = cloudflare_zero_trust_access_service_token.gitea_runner.client_id
}
output "gitea_runner_cf_access_client_secret" {
description = "CF Access service token client secret. Store in Vault at secret/gitea-runner-cf-access. Only emitted at creation time."
value = cloudflare_zero_trust_access_service_token.gitea_runner.client_secret
sensitive = true
}
+5 -7
View File
@@ -29,13 +29,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
zstd \
&& rm -rf /var/lib/apt/lists/*
# Node.js 20 LTS via binary tarball (nodesource apt repo is unreliable on Ubuntu 24.04)
RUN NODE_VERSION=20.19.1 \
&& curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" \
| tar -xJ -C /usr/local --strip-components=1 \
&& node --version \
&& npm --version \
&& npm install -g yarn
# Node.js 20 LTS — required to execute Forgejo JS actions (checkout, upload-artifact, cache, etc.)
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g yarn \
&& rm -rf /var/lib/apt/lists/*
# Python 3 + pip + venv
RUN apt-get update && apt-get install -y --no-install-recommends \
@@ -25,8 +25,19 @@ spec:
type: RuntimeDefault
containers:
- name: dharma
image: registry.neuralplatform.ai/neuron-technologies/dharma:latest
imagePullPolicy: Always
# Pinned to a content-addressable SHA tag instead of :latest so the
# deployed image is deterministic and rollback is `git revert`. The
# tag is produced by the dharma-el ci-prod.yaml workflow on every
# push to main: registry.neuralplatform.ai/neuron-technologies/
# dharma:<short-sha>.
#
# PINNED_BY_NEXT_BUILD is a deliberate placeholder. It will fail to
# pull (ImagePullBackOff) until a human replaces it with a real
# short SHA from a successful ci-prod run. That failure is the
# forcing function: the only way prod gets a new image is by
# opening a PR that names a real, built tag.
image: registry.neuralplatform.ai/neuron-technologies/dharma:PINNED_BY_NEXT_BUILD
imagePullPolicy: Always # redundant once on SHA tags; remove in a follow-up
ports:
- name: http
containerPort: 8765
@@ -14,6 +14,5 @@ spec:
services:
- name: dharma
port: 8765
# TLS terminates at Cloudflare; tunnel reaches Traefik with noTLSVerify.
# Traefik websecure entrypoint has its own default cert (no resolver
# configured in this cluster), matching every other neuron-prod IngressRoute.
tls:
certResolver: letsencrypt