chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,683 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "sim.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "sim.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "sim.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "sim.labels" -}}
|
||||
helm.sh/chart: {{ include "sim.chart" . }}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- with .Values.global.commonLabels }}
|
||||
{{ toYaml . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "sim.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "sim.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
App specific labels
|
||||
*/}}
|
||||
{{- define "sim.app.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: app
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
App selector labels
|
||||
*/}}
|
||||
{{- define "sim.app.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: app
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Realtime specific labels
|
||||
*/}}
|
||||
{{- define "sim.realtime.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: realtime
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Realtime selector labels
|
||||
*/}}
|
||||
{{- define "sim.realtime.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: realtime
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL specific labels
|
||||
*/}}
|
||||
{{- define "sim.postgresql.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: postgresql
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL selector labels
|
||||
*/}}
|
||||
{{- define "sim.postgresql.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: postgresql
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Ollama specific labels
|
||||
*/}}
|
||||
{{- define "sim.ollama.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: ollama
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Ollama selector labels
|
||||
*/}}
|
||||
{{- define "sim.ollama.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: ollama
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PII (Presidio) specific labels
|
||||
*/}}
|
||||
{{- define "sim.pii.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: pii
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PII (Presidio) selector labels
|
||||
*/}}
|
||||
{{- define "sim.pii.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: pii
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Migrations specific labels
|
||||
*/}}
|
||||
{{- define "sim.migrations.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: migrations
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot specific labels
|
||||
*/}}
|
||||
{{- define "sim.copilot.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: copilot
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot selector labels
|
||||
*/}}
|
||||
{{- define "sim.copilot.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: copilot
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot PostgreSQL specific labels
|
||||
*/}}
|
||||
{{- define "sim.copilotPostgresql.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: copilot-postgresql
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot PostgreSQL selector labels
|
||||
*/}}
|
||||
{{- define "sim.copilotPostgresql.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: copilot-postgresql
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "sim.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "sim.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create image name with optional registry and digest pinning.
|
||||
Accepts a context dict with:
|
||||
imageRoot — the image object (repository, optional tag, optional digest, pullPolicy)
|
||||
global — .Values.global (for imageRegistry and useRegistryForAllImages)
|
||||
chartAppVersion — .Chart.AppVersion (used as default tag when imageRoot.tag is empty)
|
||||
|
||||
Resolution order:
|
||||
1. If imageRoot.digest is set, render "<registry?/>repo@<digest>"
|
||||
2. Else render "<registry?/>repo:<tag>" where tag defaults to chartAppVersion
|
||||
Usage: {{ include "sim.image" (dict "imageRoot" .Values.app.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
*/}}
|
||||
{{- define "sim.image" -}}
|
||||
{{- $imageRoot := .imageRoot -}}
|
||||
{{- $global := .global -}}
|
||||
{{- $repository := $imageRoot.repository -}}
|
||||
{{- $digest := $imageRoot.digest | default "" -}}
|
||||
{{- $tag := $imageRoot.tag | default "" | toString -}}
|
||||
{{- if and (eq $tag "") (eq $digest "") -}}
|
||||
{{- $tag = .chartAppVersion | default "" | toString -}}
|
||||
{{- end -}}
|
||||
{{- $registry := "" -}}
|
||||
{{- if and $global $global.imageRegistry -}}
|
||||
{{- if or (hasPrefix "simstudioai/" $repository) $global.useRegistryForAllImages -}}
|
||||
{{- $registry = $global.imageRegistry -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- $repoPath := $repository -}}
|
||||
{{- if $registry -}}
|
||||
{{- $repoPath = printf "%s/%s" $registry $repository -}}
|
||||
{{- end -}}
|
||||
{{- if ne $digest "" -}}
|
||||
{{- printf "%s@%s" $repoPath $digest }}
|
||||
{{- else -}}
|
||||
{{- $resolvedTag := required (printf "sim.image: no tag or digest resolvable for %q (set imageRoot.tag, imageRoot.digest, or Chart.AppVersion)" $repository) $tag -}}
|
||||
{{- printf "%s:%s" $repoPath $resolvedTag }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Database URL for internal PostgreSQL
|
||||
*/}}
|
||||
{{- define "sim.databaseUrl" -}}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
{{- $host := printf "%s-postgresql" (include "sim.fullname" .) }}
|
||||
{{- $port := .Values.postgresql.service.port }}
|
||||
{{- $username := .Values.postgresql.auth.username }}
|
||||
{{- $database := .Values.postgresql.auth.database }}
|
||||
{{- $sslMode := ternary "require" "disable" .Values.postgresql.tls.enabled }}
|
||||
{{- printf "postgresql://%s:$(POSTGRES_PASSWORD)@%s:%v/%s?sslmode=%s" $username $host $port $database $sslMode }}
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
{{- $host := .Values.externalDatabase.host }}
|
||||
{{- $port := .Values.externalDatabase.port }}
|
||||
{{- $username := .Values.externalDatabase.username }}
|
||||
{{- $database := .Values.externalDatabase.database }}
|
||||
{{- $sslMode := .Values.externalDatabase.sslMode }}
|
||||
{{- printf "postgresql://%s:$(EXTERNAL_DB_PASSWORD)@%s:%v/%s?sslmode=%s" $username $host $port $database $sslMode }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate required secrets and reject default placeholder values
|
||||
Skip validation when using existing secrets or External Secrets Operator
|
||||
*/}}
|
||||
{{- define "sim.validateSecrets" -}}
|
||||
{{- $useExistingAppSecret := and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- $useExistingPostgresSecret := and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled }}
|
||||
{{- $useExistingExternalDbSecret := and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled }}
|
||||
{{- /* App secrets validation - skip if using existing secret or ESO */ -}}
|
||||
{{- if not (or $useExistingAppSecret $useExternalSecrets) }}
|
||||
{{- if and .Values.app.enabled (not .Values.app.env.BETTER_AUTH_SECRET) }}
|
||||
{{- fail "app.env.BETTER_AUTH_SECRET is required for production deployment" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.app.enabled (eq .Values.app.env.BETTER_AUTH_SECRET "CHANGE-ME-32-CHAR-SECRET-FOR-PRODUCTION-USE") }}
|
||||
{{- fail "app.env.BETTER_AUTH_SECRET must not use the default placeholder value. Generate a secure secret with: openssl rand -hex 32" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.app.enabled (not .Values.app.env.ENCRYPTION_KEY) }}
|
||||
{{- fail "app.env.ENCRYPTION_KEY is required for production deployment" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.app.enabled (eq .Values.app.env.ENCRYPTION_KEY "CHANGE-ME-32-CHAR-ENCRYPTION-KEY-FOR-PROD") }}
|
||||
{{- fail "app.env.ENCRYPTION_KEY must not use the default placeholder value. Generate a secure key with: openssl rand -hex 32" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.app.enabled (not .Values.app.env.INTERNAL_API_SECRET) }}
|
||||
{{- fail "app.env.INTERNAL_API_SECRET is required for production deployment (shared auth between sim-app and sim-realtime pods). Generate one with: openssl rand -hex 32" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.realtime.enabled (eq .Values.realtime.env.BETTER_AUTH_SECRET "CHANGE-ME-32-CHAR-SECRET-FOR-PRODUCTION-USE") }}
|
||||
{{- fail "realtime.env.BETTER_AUTH_SECRET must not use the default placeholder value. Generate a secure secret with: openssl rand -hex 32" }}
|
||||
{{- end }}
|
||||
{{- /* CRON_SECRET is required when cronjobs are enabled — pods reference it via secretKeyRef and would fail to start if the key is missing from the Secret. */ -}}
|
||||
{{- if and .Values.cronjobs.enabled (not .Values.app.env.CRON_SECRET) }}
|
||||
{{- fail "app.env.CRON_SECRET is required when cronjobs.enabled=true (every cron pod authenticates with this token). Generate one with: openssl rand -hex 32, or set cronjobs.enabled=false." }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /* PostgreSQL password validation - skip if using existing secret or ESO */ -}}
|
||||
{{- if not (or $useExistingPostgresSecret $useExternalSecrets) }}
|
||||
{{- if and .Values.postgresql.enabled (not .Values.postgresql.auth.password) }}
|
||||
{{- fail "postgresql.auth.password is required when using internal PostgreSQL" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.postgresql.enabled (eq .Values.postgresql.auth.password "CHANGE-ME-SECURE-PASSWORD") }}
|
||||
{{- fail "postgresql.auth.password must not use the default placeholder value. Set a secure password for production" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.postgresql.enabled .Values.postgresql.auth.password (not (regexMatch "^[a-zA-Z0-9._-]+$" .Values.postgresql.auth.password)) }}
|
||||
{{- fail "postgresql.auth.password must only contain alphanumeric characters, hyphens, underscores, or periods to ensure DATABASE_URL compatibility. Generate with: openssl rand -base64 16 | tr -d '/+='" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /* External database password validation - skip if using existing secret or ESO */ -}}
|
||||
{{- if not (or $useExistingExternalDbSecret $useExternalSecrets) }}
|
||||
{{- if and .Values.externalDatabase.enabled (not .Values.externalDatabase.password) }}
|
||||
{{- fail "externalDatabase.password is required when using external database" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.externalDatabase.enabled .Values.externalDatabase.password (not (regexMatch "^[a-zA-Z0-9._-]+$" .Values.externalDatabase.password)) }}
|
||||
{{- fail "externalDatabase.password must only contain alphanumeric characters, hyphens, underscores, or periods to ensure DATABASE_URL compatibility." }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /* ESO coverage validation - every key set in app.env / realtime.env must be mapped in externalSecrets.remoteRefs.app */ -}}
|
||||
{{- include "sim.validateExternalSecretCoverage" . }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate that every key set in app.env / realtime.env is also mapped in
|
||||
externalSecrets.remoteRefs.app when ESO is enabled. When ESO is on, the
|
||||
chart-managed Secret is not rendered — anything not mapped via ESO would
|
||||
be silently missing at runtime.
|
||||
|
||||
Chart-computed keys (DATABASE_URL, SOCKET_SERVER_URL, OLLAMA_URL, PII_URL)
|
||||
are exempt because they're inlined on the container, not sourced from the
|
||||
Secret.
|
||||
|
||||
Fail-fast is only safe for ESO because we can introspect remoteRefs at
|
||||
template time. For existingSecret we cannot read the user's pre-created
|
||||
Secret, so coverage there is documented (values.yaml + README) rather
|
||||
than enforced.
|
||||
*/}}
|
||||
{{- define "sim.validateExternalSecretCoverage" -}}
|
||||
{{- if and .Values.externalSecrets .Values.externalSecrets.enabled -}}
|
||||
{{- $remoteRefs := default (dict) (default (dict) .Values.externalSecrets.remoteRefs).app -}}
|
||||
{{- $chartComputed := list "DATABASE_URL" "SOCKET_SERVER_URL" "OLLAMA_URL" "PII_URL" -}}
|
||||
{{- $appEnv := default (dict) .Values.app.env -}}
|
||||
{{/*
|
||||
Required-key coverage: these are non-optional at runtime. With ESO enabled
|
||||
the chart-managed Secret is not rendered, so a missing key surfaces as a
|
||||
runtime CrashLoopBackOff with cryptic env errors. Fail at template time
|
||||
if the key is neither set in app.env nor mapped via remoteRefs.app.
|
||||
*/}}
|
||||
{{- if .Values.app.enabled -}}
|
||||
{{- $required := list "BETTER_AUTH_SECRET" "ENCRYPTION_KEY" "INTERNAL_API_SECRET" -}}
|
||||
{{- if .Values.cronjobs.enabled -}}
|
||||
{{- $required = append $required "CRON_SECRET" -}}
|
||||
{{- end -}}
|
||||
{{- range $key := $required -}}
|
||||
{{- $inEnv := index $appEnv $key -}}
|
||||
{{- $mapped := index $remoteRefs $key -}}
|
||||
{{- if and (or (not $inEnv) (eq (toString $inEnv) "") (eq (toString $inEnv) "<nil>")) (not $mapped) -}}
|
||||
{{- fail (printf "Required key '%s' is missing: externalSecrets.enabled=true but the key is neither set in app.env nor mapped in externalSecrets.remoteRefs.app. Map it via externalSecrets.remoteRefs.app.%s='path/in/store' so it is synced into the app Secret." $key $key) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if .Values.app.enabled -}}
|
||||
{{- range $key, $value := default (dict) .Values.app.env -}}
|
||||
{{- if not (has $key $chartComputed) -}}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") -}}
|
||||
{{- $mapped := index $remoteRefs $key -}}
|
||||
{{- if not $mapped -}}
|
||||
{{- fail (printf "Key '%s' is set in app.env but externalSecrets.enabled=true and externalSecrets.remoteRefs.app.%s is not configured. When ESO is enabled the chart-managed app Secret is not rendered, so the container would start with no value. Either map it via externalSecrets.remoteRefs.app.%s='path/in/store' or remove it from app.env." $key $key $key) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if .Values.realtime.enabled -}}
|
||||
{{- range $key, $value := default (dict) .Values.realtime.env -}}
|
||||
{{- if not (has $key $chartComputed) -}}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") -}}
|
||||
{{- $mapped := index $remoteRefs $key -}}
|
||||
{{- if not $mapped -}}
|
||||
{{- fail (printf "Key '%s' is set in realtime.env but externalSecrets.enabled=true and externalSecrets.remoteRefs.app.%s is not configured. Either map it via externalSecrets.remoteRefs.app.%s='path/in/store' or remove it from realtime.env." $key $key $key) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the app secrets name
|
||||
Returns the name of the secret containing app credentials (auth, encryption keys)
|
||||
*/}}
|
||||
{{- define "sim.appSecretName" -}}
|
||||
{{- if and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled -}}
|
||||
{{- .Values.app.secrets.existingSecret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-app-secrets" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the PostgreSQL secret name
|
||||
Returns the name of the secret containing PostgreSQL password
|
||||
*/}}
|
||||
{{- define "sim.postgresqlSecretName" -}}
|
||||
{{- if and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled -}}
|
||||
{{- .Values.postgresql.auth.existingSecret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-postgresql-secret" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the PostgreSQL password key name
|
||||
Returns the key name in the secret that contains the password
|
||||
*/}}
|
||||
{{- define "sim.postgresqlPasswordKey" -}}
|
||||
{{- if and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled -}}
|
||||
{{- .Values.postgresql.auth.existingSecret.passwordKey | default "POSTGRES_PASSWORD" -}}
|
||||
{{- else -}}
|
||||
{{- print "POSTGRES_PASSWORD" -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the external database secret name
|
||||
Returns the name of the secret containing external database password
|
||||
*/}}
|
||||
{{- define "sim.externalDbSecretName" -}}
|
||||
{{- if and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled -}}
|
||||
{{- .Values.externalDatabase.existingSecret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-external-db-secret" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the external database password key name
|
||||
Returns the key name in the secret that contains the password
|
||||
*/}}
|
||||
{{- define "sim.externalDbPasswordKey" -}}
|
||||
{{- if and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled -}}
|
||||
{{- .Values.externalDatabase.existingSecret.passwordKey | default "EXTERNAL_DB_PASSWORD" -}}
|
||||
{{- else -}}
|
||||
{{- print "EXTERNAL_DB_PASSWORD" -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Check if app secrets should be created by the chart
|
||||
Returns true if we should create the app secrets (not using existing or ESO)
|
||||
*/}}
|
||||
{{- define "sim.createAppSecrets" -}}
|
||||
{{- $useExistingAppSecret := and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- if not (or $useExistingAppSecret $useExternalSecrets) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Check if PostgreSQL secret should be created by the chart
|
||||
Returns true if we should create the PostgreSQL secret (not using existing or ESO)
|
||||
*/}}
|
||||
{{- define "sim.createPostgresqlSecret" -}}
|
||||
{{- $useExistingSecret := and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- if not (or $useExistingSecret $useExternalSecrets) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Check if external database secret should be created by the chart
|
||||
Returns true if we should create the external database secret (not using existing or ESO)
|
||||
*/}}
|
||||
{{- define "sim.createExternalDbSecret" -}}
|
||||
{{- $useExistingSecret := and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- if not (or $useExistingSecret $useExternalSecrets) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Ollama URL
|
||||
*/}}
|
||||
{{- define "sim.ollamaUrl" -}}
|
||||
{{- if .Values.ollama.enabled }}
|
||||
{{- $serviceName := printf "%s-ollama" (include "sim.fullname" .) }}
|
||||
{{- $port := .Values.ollama.service.port }}
|
||||
{{- printf "http://%s:%v" $serviceName $port }}
|
||||
{{- else }}
|
||||
{{- .Values.app.env.OLLAMA_URL | default "http://localhost:11434" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PII (Presidio) service URL
|
||||
*/}}
|
||||
{{- define "sim.piiUrl" -}}
|
||||
{{- if .Values.pii.enabled }}
|
||||
{{- $serviceName := printf "%s-pii" (include "sim.fullname" .) }}
|
||||
{{- $port := .Values.pii.service.port }}
|
||||
{{- printf "http://%s:%v" $serviceName $port }}
|
||||
{{- else }}
|
||||
{{- .Values.app.env.PII_URL | default "http://localhost:5001" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Socket Server URL (internal)
|
||||
*/}}
|
||||
{{- define "sim.socketServerUrl" -}}
|
||||
{{- if .Values.realtime.enabled }}
|
||||
{{- $serviceName := printf "%s-realtime" (include "sim.fullname" .) }}
|
||||
{{- $port := .Values.realtime.service.port }}
|
||||
{{- printf "http://%s:%v" $serviceName $port }}
|
||||
{{- else }}
|
||||
{{- .Values.app.env.SOCKET_SERVER_URL | default "http://localhost:3002" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Resource limits and requests
|
||||
*/}}
|
||||
{{- define "sim.resources" -}}
|
||||
{{- if .resources }}
|
||||
resources:
|
||||
{{- if .resources.limits }}
|
||||
limits:
|
||||
{{- toYaml .resources.limits | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .resources.requests }}
|
||||
requests:
|
||||
{{- toYaml .resources.requests | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Pod-level security context with Pod Security Standards "restricted" defaults.
|
||||
User-supplied `.podSecurityContext` values override defaults (user wins).
|
||||
Usage: {{ include "sim.podSecurityContext" .Values.app | nindent 6 }}
|
||||
*/}}
|
||||
{{- define "sim.podSecurityContext" -}}
|
||||
{{- $defaults := dict "runAsNonRoot" true "runAsUser" 1001 "runAsGroup" 1001 "fsGroup" 1001 "seccompProfile" (dict "type" "RuntimeDefault") -}}
|
||||
{{- $user := default (dict) .podSecurityContext -}}
|
||||
{{- $merged := mergeOverwrite (deepCopy $defaults) $user -}}
|
||||
securityContext:
|
||||
{{- toYaml $merged | nindent 2 }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Container-level security context with Pod Security Standards "restricted" defaults.
|
||||
User-supplied `.securityContext` values override defaults (user wins).
|
||||
`readOnlyRootFilesystem` is intentionally NOT defaulted — set it per-workload in values
|
||||
when the container can tolerate a read-only root (Next.js writes to `.next/cache`,
|
||||
Postgres writes to `/var/lib/postgresql/data`, so they're left writable by default).
|
||||
Usage: {{ include "sim.containerSecurityContext" .Values.app | nindent 10 }}
|
||||
*/}}
|
||||
{{- define "sim.containerSecurityContext" -}}
|
||||
{{- $defaults := dict "runAsNonRoot" true "allowPrivilegeEscalation" false "capabilities" (dict "drop" (list "ALL")) "seccompProfile" (dict "type" "RuntimeDefault") -}}
|
||||
{{- $user := default (dict) .securityContext -}}
|
||||
{{- $merged := mergeOverwrite (deepCopy $defaults) $user -}}
|
||||
securityContext:
|
||||
{{- toYaml $merged | nindent 2 }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Backwards-compatible alias for container security context.
|
||||
*/}}
|
||||
{{- define "sim.securityContext" -}}
|
||||
{{- include "sim.containerSecurityContext" . }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Node selector
|
||||
*/}}
|
||||
{{- define "sim.nodeSelector" -}}
|
||||
{{- if .nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml .nodeSelector | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Tolerations
|
||||
*/}}
|
||||
{{- define "sim.tolerations" -}}
|
||||
{{- if .tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml .tolerations | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Affinity
|
||||
*/}}
|
||||
{{- define "sim.affinity" -}}
|
||||
{{- if .affinity }}
|
||||
affinity:
|
||||
{{- toYaml .affinity | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Topology spread constraints — spreads pods across failure domains.
|
||||
Pass the per-component spec (.Values.app, .Values.realtime, ...). Users supply
|
||||
the full constraint list including labelSelector; pattern mirrors affinity.
|
||||
Usage: {{ include "sim.topologySpreadConstraints" .Values.app | nindent 6 }}
|
||||
*/}}
|
||||
{{- define "sim.topologySpreadConstraints" -}}
|
||||
{{- if .topologySpreadConstraints }}
|
||||
topologySpreadConstraints:
|
||||
{{- toYaml .topologySpreadConstraints | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot environment secret name
|
||||
*/}}
|
||||
{{- define "sim.copilot.envSecretName" -}}
|
||||
{{- if and .Values.copilot.server.secret.name (ne .Values.copilot.server.secret.name "") -}}
|
||||
{{- .Values.copilot.server.secret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-copilot-env" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot database secret name
|
||||
*/}}
|
||||
{{- define "sim.copilot.databaseSecretName" -}}
|
||||
{{- if .Values.copilot.postgresql.enabled -}}
|
||||
{{- printf "%s-copilot-postgresql-secret" (include "sim.fullname" .) -}}
|
||||
{{- else if and .Values.copilot.database.existingSecretName (ne .Values.copilot.database.existingSecretName "") -}}
|
||||
{{- .Values.copilot.database.existingSecretName -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-copilot-database-secret" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot database secret key
|
||||
*/}}
|
||||
{{- define "sim.copilot.databaseSecretKey" -}}
|
||||
{{- default "DATABASE_URL" .Values.copilot.database.secretKey -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate Copilot configuration
|
||||
*/}}
|
||||
{{- define "sim.copilot.validate" -}}
|
||||
{{- if .Values.copilot.enabled -}}
|
||||
{{- if and (not .Values.copilot.server.secret.create) (or (not .Values.copilot.server.secret.name) (eq .Values.copilot.server.secret.name "")) -}}
|
||||
{{- fail "copilot.server.secret.name must be provided when copilot.server.secret.create=false" -}}
|
||||
{{- end -}}
|
||||
{{- if .Values.copilot.server.secret.create -}}
|
||||
{{- $env := .Values.copilot.server.env -}}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled -}}
|
||||
{{- $remoteRefs := default (dict) (default (dict) .Values.externalSecrets.remoteRefs).copilot -}}
|
||||
{{- $required := list "AGENT_API_DB_ENCRYPTION_KEY" "INTERNAL_API_SECRET" "LICENSE_KEY" "SIM_BASE_URL" "SIM_AGENT_API_KEY" "REDIS_URL" -}}
|
||||
{{- range $key := $required -}}
|
||||
{{- $inEnv := and $env (index $env $key) (ne (index $env $key) "") -}}
|
||||
{{- $mapped := index $remoteRefs $key -}}
|
||||
{{- if not (or $inEnv (and $useExternalSecrets $mapped)) -}}
|
||||
{{- if $useExternalSecrets -}}
|
||||
{{- fail (printf "Required key '%s' is missing: externalSecrets.enabled=true but the key is neither set in copilot.server.env nor mapped in externalSecrets.remoteRefs.copilot. Map it via externalSecrets.remoteRefs.copilot.%s='path/in/store' so it is synced into the copilot Secret." $key $key) -}}
|
||||
{{- else -}}
|
||||
{{- fail (printf "copilot.server.env.%s is required when copilot is enabled" $key) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if $useExternalSecrets -}}
|
||||
{{- range $key, $value := $env -}}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") -}}
|
||||
{{- if not (index $remoteRefs $key) -}}
|
||||
{{- fail (printf "Key '%s' is set in copilot.server.env but externalSecrets.enabled=true and externalSecrets.remoteRefs.copilot.%s is not configured. When ESO is enabled the chart-managed copilot Secret is not rendered, so the container would start with no value. Either map it via externalSecrets.remoteRefs.copilot.%s='path/in/store' or remove it from copilot.server.env." $key $key $key) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- $hasOpenAI := or (and $env (ne (default "" (index $env "OPENAI_API_KEY_1")) "")) (and $useExternalSecrets (index $remoteRefs "OPENAI_API_KEY_1")) -}}
|
||||
{{- $hasAnthropic := or (and $env (ne (default "" (index $env "ANTHROPIC_API_KEY_1")) "")) (and $useExternalSecrets (index $remoteRefs "ANTHROPIC_API_KEY_1")) -}}
|
||||
{{- if not (or $hasOpenAI $hasAnthropic) -}}
|
||||
{{- fail "Set at least one of copilot.server.env.OPENAI_API_KEY_1 or copilot.server.env.ANTHROPIC_API_KEY_1 (or map one via externalSecrets.remoteRefs.copilot when externalSecrets.enabled=true)" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if .Values.copilot.postgresql.enabled -}}
|
||||
{{- if or (not .Values.copilot.postgresql.auth.password) (eq .Values.copilot.postgresql.auth.password "") -}}
|
||||
{{- fail "copilot.postgresql.auth.password is required when copilot.postgresql.enabled=true" -}}
|
||||
{{- end -}}
|
||||
{{- else -}}
|
||||
{{- if and (or (not .Values.copilot.database.existingSecretName) (eq .Values.copilot.database.existingSecretName "")) (or (not .Values.copilot.database.url) (eq .Values.copilot.database.url "")) -}}
|
||||
{{- fail "Provide copilot.database.existingSecretName or copilot.database.url when copilot.postgresql.enabled=false" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
Reference in New Issue
Block a user