From b9887e1cc2d4a68a285620f06e61ef78ac81acbb Mon Sep 17 00:00:00 2001 From: Erik Weathers <1111441+erikdw@users.noreply.github.com> Date: Tue, 20 Oct 2026 21:28:10 -0700 Subject: [PATCH 1/4] Fail Google HMAC renders that drop the GCS region. S3-compatible GCS needs AWS_REGION. Write it from objectStorage.google.region so a later api.extraEnvVars replacement cannot remove it, and fail the render when neither that value nor an explicit AWS_REGION is set. Co-authored-by: Cursor --- braintrust/ci/values-google.yaml | 1 + .../examples/google-autopilot-cel/values.yaml | 5 +- .../examples/google-autopilot/values.yaml | 6 +- .../examples/google-standard/values.yaml | 6 +- braintrust/templates/api-configmap.yaml | 19 ++++ .../tests/__fixtures__/google-values.yaml | 1 + braintrust/tests/api-autoscaling_test.yaml | 17 ++++ braintrust/tests/api-configmap_test.yaml | 94 +++++++++++++++++++ braintrust/values.yaml | 5 + 9 files changed, 143 insertions(+), 11 deletions(-) diff --git a/braintrust/ci/values-google.yaml b/braintrust/ci/values-google.yaml index 22c2127..96f7273 100644 --- a/braintrust/ci/values-google.yaml +++ b/braintrust/ci/values-google.yaml @@ -17,6 +17,7 @@ objectStorage: google: brainstoreBucket: "test-brainstore-bucket" apiBucket: "test-api-bucket" + region: "us-central1" api: name: "braintrust-api" diff --git a/braintrust/examples/google-autopilot-cel/values.yaml b/braintrust/examples/google-autopilot-cel/values.yaml index 4db82cb..317f896 100644 --- a/braintrust/examples/google-autopilot-cel/values.yaml +++ b/braintrust/examples/google-autopilot-cel/values.yaml @@ -14,6 +14,8 @@ objectStorage: google: brainstoreBucket: "" apiBucket: "" + # Required for S3-compatible GCS. Rendered as AWS_REGION and AWS_DEFAULT_REGION. + region: "us-central1" api: name: "braintrust-api" @@ -57,9 +59,6 @@ api: tmpVolume: enabled: true sizeLimit: "1Gi" - extraEnvVars: - - name: AWS_REGION - value: "us-central1" brainstore: serviceAccount: diff --git a/braintrust/examples/google-autopilot/values.yaml b/braintrust/examples/google-autopilot/values.yaml index 0ee727d..25a87d1 100644 --- a/braintrust/examples/google-autopilot/values.yaml +++ b/braintrust/examples/google-autopilot/values.yaml @@ -17,6 +17,8 @@ objectStorage: google: brainstoreBucket: "" apiBucket: "" + # Required for S3-compatible GCS. Rendered as AWS_REGION and AWS_DEFAULT_REGION. + region: "us-central1" # BTQL query.read audit logging (requires data plane v2.6.0+). # Uncomment exactly one block to enable audit logging for specific orgs. @@ -61,10 +63,6 @@ api: limits: cpu: "4" memory: "8Gi" - extraEnvVars: - # For S3-compatible GCS Storage, set the AWS_REGION environment variable to the region of your GCS bucket - - name: AWS_REGION - value: "us-central1" # Brainstore configuration (split into reader and writer) brainstore: diff --git a/braintrust/examples/google-standard/values.yaml b/braintrust/examples/google-standard/values.yaml index a1ee0d9..496b6fd 100644 --- a/braintrust/examples/google-standard/values.yaml +++ b/braintrust/examples/google-standard/values.yaml @@ -22,6 +22,8 @@ objectStorage: google: brainstoreBucket: "" apiBucket: "" + # Required for S3-compatible GCS. Rendered as AWS_REGION and AWS_DEFAULT_REGION. + region: "us-central1" api: name: "braintrust-api" @@ -51,10 +53,6 @@ api: limits: cpu: "4" memory: "8Gi" - extraEnvVars: - # For S3-compatible GCS Storage, set the AWS_REGION environment variable to the region of your GCS bucket - - name: AWS_REGION - value: "us-central1" # Brainstore configuration (split into reader and writer) brainstore: diff --git a/braintrust/templates/api-configmap.yaml b/braintrust/templates/api-configmap.yaml index 41643ba..42e3672 100644 --- a/braintrust/templates/api-configmap.yaml +++ b/braintrust/templates/api-configmap.yaml @@ -9,6 +9,21 @@ {{- if and (or (eq $orgName "") (eq $orgName "*")) (eq $primaryOrgName "") (not $hasPrimaryOrgNameExtraEnv) -}} {{- fail "global.primaryOrgName or api.extraEnvVars PRIMARY_ORG_NAME is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." -}} {{- end -}} +{{- $googleRegion := "" -}} +{{- if eq (.Values.cloud | default "") "google" -}} +{{- $googleRegion = .Values.objectStorage.google.region | default "" | toString | trim -}} +{{- end -}} +{{- if and (eq (.Values.cloud | default "") "google") (not .Values.api.enableGcsAuth) -}} +{{- $hasAwsRegionExtraEnv := false -}} +{{- range .Values.api.extraEnvVars -}} +{{- if eq (.name | default "" | toString) "AWS_REGION" -}} +{{- $hasAwsRegionExtraEnv = true -}} +{{- end -}} +{{- end -}} +{{- if and (eq $googleRegion "") (not $hasAwsRegionExtraEnv) -}} +{{- fail "objectStorage.google.region or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." -}} +{{- end -}} +{{- end -}} {{- $allowedOrgIds := .Values.global.allowedOrgIds | default "" | toString | trim -}} {{- $btqlStrictOrgIds := .Values.btqlAuditLogsStrictOrgIds | default list -}} {{- $btqlBestEffortOrgIds := .Values.btqlAuditLogsBestEffortOrgIds | default list -}} @@ -70,6 +85,10 @@ data: AWS_ENDPOINT_URL: "https://storage.googleapis.com" AWS_REQUEST_CHECKSUM_CALCULATION: "WHEN_REQUIRED" AWS_RESPONSE_CHECKSUM_VALIDATION: "WHEN_REQUIRED" + {{- if $googleRegion }} + AWS_REGION: {{ $googleRegion | quote }} + AWS_DEFAULT_REGION: {{ $googleRegion | quote }} + {{- end }} {{- end }} {{- end }} diff --git a/braintrust/tests/__fixtures__/google-values.yaml b/braintrust/tests/__fixtures__/google-values.yaml index 8655dd0..b17263f 100644 --- a/braintrust/tests/__fixtures__/google-values.yaml +++ b/braintrust/tests/__fixtures__/google-values.yaml @@ -10,6 +10,7 @@ objectStorage: google: brainstoreBucket: "test-brainstore-bucket" apiBucket: "test-api-bucket" + region: "us-central1" brainstore: serviceAccount: diff --git a/braintrust/tests/api-autoscaling_test.yaml b/braintrust/tests/api-autoscaling_test.yaml index cb22f4c..0d7bbd6 100644 --- a/braintrust/tests/api-autoscaling_test.yaml +++ b/braintrust/tests/api-autoscaling_test.yaml @@ -14,6 +14,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: false release: namespace: "braintrust" @@ -27,6 +28,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: false release: namespace: "braintrust" @@ -53,6 +55,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true release: namespace: "braintrust" @@ -96,6 +99,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true release: namespace: "braintrust" @@ -157,6 +161,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.replicas: 4 release: @@ -184,6 +189,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.extraEnvVars: - name: ENABLE_PROMETHEUS_METRICS @@ -206,6 +212,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: false api.replicas: 4 release: @@ -230,6 +237,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -244,6 +252,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -268,6 +277,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -295,6 +305,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -319,6 +330,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -340,6 +352,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -362,6 +375,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true api.workloadIsolation.ingest.autoscaling.enabled: false @@ -382,6 +396,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true api.workloadIsolation.ingest.autoscaling.enabled: false @@ -397,6 +412,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true api.workloadIsolation.ingest.autoscaling.enabled: false @@ -422,6 +438,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google + objectStorage.google.region: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true api.workloadIsolation.ingest.autoscaling.enabled: false diff --git a/braintrust/tests/api-configmap_test.yaml b/braintrust/tests/api-configmap_test.yaml index 27de0d0..fb87f04 100644 --- a/braintrust/tests/api-configmap_test.yaml +++ b/braintrust/tests/api-configmap_test.yaml @@ -262,6 +262,79 @@ tests: - equal: path: data.AWS_RESPONSE_CHECKSUM_VALIDATION value: "WHEN_REQUIRED" + - equal: + path: data.AWS_REGION + value: "us-central1" + - equal: + path: data.AWS_DEFAULT_REGION + value: "us-central1" + + - it: should keep the GCS region when extraEnvVars replaces the list + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + api.extraEnvVars: + - name: ENABLE_CONTAINER_CPU_METRICS + value: "true" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.AWS_REGION + value: "us-central1" + - equal: + path: data.AWS_DEFAULT_REGION + value: "us-central1" + + - it: should trim the GCS region + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + objectStorage.google.region: " us-central1 " + release: + namespace: "braintrust" + asserts: + - equal: + path: data.AWS_REGION + value: "us-central1" + - equal: + path: data.AWS_DEFAULT_REGION + value: "us-central1" + + - it: should allow a Google HMAC deployment that sets AWS_REGION via extraEnvVars + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + objectStorage.google.region: "" + api.extraEnvVars: + - name: AWS_REGION + value: "us-central1" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.AWS_ENDPOINT_URL + value: "https://storage.googleapis.com" + - isNull: + path: data.AWS_REGION + - isNull: + path: data.AWS_DEFAULT_REGION + + - it: should reject a Google HMAC deployment with no region + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + objectStorage.google.region: "" + api.extraEnvVars: [] + release: + namespace: "braintrust" + asserts: + - failedTemplate: + errorMessage: "objectStorage.google.region or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." - it: should not set checksum vars when enableGcsAuth is true values: @@ -282,6 +355,27 @@ tests: path: data.AWS_REQUEST_CHECKSUM_CALCULATION - isNull: path: data.AWS_RESPONSE_CHECKSUM_VALIDATION + - isNull: + path: data.AWS_REGION + - isNull: + path: data.AWS_DEFAULT_REGION + + - it: should not require a GCS region when enableGcsAuth is true + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + api.enableGcsAuth: true + api.serviceAccount.googleServiceAccount: "test@project.iam.gserviceaccount.com" + objectStorage.google.region: "" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.ENABLE_GCS_AUTH + value: "true" + - isNull: + path: data.AWS_REGION - it: should configure brainstore URLs correctly values: diff --git a/braintrust/values.yaml b/braintrust/values.yaml index d91754f..299dc19 100644 --- a/braintrust/values.yaml +++ b/braintrust/values.yaml @@ -74,6 +74,11 @@ objectStorage: brainstoreBucket: "" # Single API bucket with paths for responses and code bundles apiBucket: "" + # GCS bucket region. Required for S3-compatible HMAC access + # (api.enableGcsAuth false). Rendered as AWS_REGION and + # AWS_DEFAULT_REGION on the API. api.extraEnvVars can still override + # AWS_REGION, but replacing that list does not remove this value. + region: "" # No-PG mode: controls which object types bypass PostgreSQL and use Brainstore directly. # Options: From 0e336057476ad61835e2553fafdf5a6dd9fad880 Mon Sep 17 00:00:00 2001 From: Erik Weathers <1111441+erikdw@users.noreply.github.com> Date: Tue, 20 Oct 2026 21:33:26 -0700 Subject: [PATCH 2/4] Concatenate module-owned env vars ahead of user env vars. Helm replaces extraEnvVars lists, so required settings such as the GCS region were wiped by customer overrides. moduleEnvVars is reserved for Terraform and rendered first. The kubelet keeps the last duplicate name, so extraEnvVars still wins. A Google HMAC deploy with no AWS_REGION in either list fails the render. Co-authored-by: Cursor --- braintrust/ci/values-google.yaml | 5 +- .../examples/google-autopilot-cel/values.yaml | 5 +- .../examples/google-autopilot/values.yaml | 6 +- .../examples/google-standard/values.yaml | 6 +- braintrust/templates/_api-deployment.tpl | 3 + braintrust/templates/_helpers.tpl | 10 +- .../templates/ai-gateway-deployment.yaml | 7 +- braintrust/templates/api-configmap.yaml | 36 ++--- ...rainstore-automationwriter-deployment.yaml | 7 +- .../brainstore-fastreader-deployment.yaml | 7 +- .../brainstore-reader-deployment.yaml | 7 +- .../brainstore-writer-deployment.yaml | 7 +- .../tests/__fixtures__/google-values.yaml | 6 +- braintrust/tests/api-autoscaling_test.yaml | 68 ++++++-- braintrust/tests/api-configmap_test.yaml | 85 +++++----- .../tests/api-workload-isolation_test.yaml | 151 ++++++++++++++++++ braintrust/tests/brainstore-writer_test.yaml | 43 +++++ braintrust/values.yaml | 25 ++- 18 files changed, 380 insertions(+), 104 deletions(-) diff --git a/braintrust/ci/values-google.yaml b/braintrust/ci/values-google.yaml index 96f7273..1b271a8 100644 --- a/braintrust/ci/values-google.yaml +++ b/braintrust/ci/values-google.yaml @@ -17,7 +17,6 @@ objectStorage: google: brainstoreBucket: "test-brainstore-bucket" apiBucket: "test-api-bucket" - region: "us-central1" api: name: "braintrust-api" @@ -43,7 +42,9 @@ api: backfillDisableNonhistorical: false allowInvalidBase64: false nodeMemoryPercent: "80" - extraEnvVars: [] + extraEnvVars: + - name: AWS_REGION + value: "us-central1" nodeSelector: {} tolerations: [] affinity: {} diff --git a/braintrust/examples/google-autopilot-cel/values.yaml b/braintrust/examples/google-autopilot-cel/values.yaml index 317f896..4db82cb 100644 --- a/braintrust/examples/google-autopilot-cel/values.yaml +++ b/braintrust/examples/google-autopilot-cel/values.yaml @@ -14,8 +14,6 @@ objectStorage: google: brainstoreBucket: "" apiBucket: "" - # Required for S3-compatible GCS. Rendered as AWS_REGION and AWS_DEFAULT_REGION. - region: "us-central1" api: name: "braintrust-api" @@ -59,6 +57,9 @@ api: tmpVolume: enabled: true sizeLimit: "1Gi" + extraEnvVars: + - name: AWS_REGION + value: "us-central1" brainstore: serviceAccount: diff --git a/braintrust/examples/google-autopilot/values.yaml b/braintrust/examples/google-autopilot/values.yaml index 25a87d1..0ee727d 100644 --- a/braintrust/examples/google-autopilot/values.yaml +++ b/braintrust/examples/google-autopilot/values.yaml @@ -17,8 +17,6 @@ objectStorage: google: brainstoreBucket: "" apiBucket: "" - # Required for S3-compatible GCS. Rendered as AWS_REGION and AWS_DEFAULT_REGION. - region: "us-central1" # BTQL query.read audit logging (requires data plane v2.6.0+). # Uncomment exactly one block to enable audit logging for specific orgs. @@ -63,6 +61,10 @@ api: limits: cpu: "4" memory: "8Gi" + extraEnvVars: + # For S3-compatible GCS Storage, set the AWS_REGION environment variable to the region of your GCS bucket + - name: AWS_REGION + value: "us-central1" # Brainstore configuration (split into reader and writer) brainstore: diff --git a/braintrust/examples/google-standard/values.yaml b/braintrust/examples/google-standard/values.yaml index 496b6fd..a1ee0d9 100644 --- a/braintrust/examples/google-standard/values.yaml +++ b/braintrust/examples/google-standard/values.yaml @@ -22,8 +22,6 @@ objectStorage: google: brainstoreBucket: "" apiBucket: "" - # Required for S3-compatible GCS. Rendered as AWS_REGION and AWS_DEFAULT_REGION. - region: "us-central1" api: name: "braintrust-api" @@ -53,6 +51,10 @@ api: limits: cpu: "4" memory: "8Gi" + extraEnvVars: + # For S3-compatible GCS Storage, set the AWS_REGION environment variable to the region of your GCS bucket + - name: AWS_REGION + value: "us-central1" # Brainstore configuration (split into reader and writer) brainstore: diff --git a/braintrust/templates/_api-deployment.tpl b/braintrust/templates/_api-deployment.tpl index 62433ff..7f639d7 100644 --- a/braintrust/templates/_api-deployment.tpl +++ b/braintrust/templates/_api-deployment.tpl @@ -231,6 +231,9 @@ spec: - name: PIP_CERT value: {{ $customCAPath | quote }} {{- end }} + {{- with $api.moduleEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} {{- with $api.extraEnvVars }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/braintrust/templates/_helpers.tpl b/braintrust/templates/_helpers.tpl index c5b85ab..d283a83 100644 --- a/braintrust/templates/_helpers.tpl +++ b/braintrust/templates/_helpers.tpl @@ -65,16 +65,23 @@ http://{{ .Values.api.service.name | default .Values.api.name }}.{{ include "bra {{/* Build one API pool from the shared api values plus pool-specific overrides. -Pool extraEnvVars are appended so shared provider configuration is retained. +Pool moduleEnvVars and extraEnvVars are appended so shared provider +configuration is retained. moduleEnvVars stay ahead of extraEnvVars. +The kubelet keeps the last duplicate env name, so a user extraEnvVars +entry overrides a moduleEnvVars entry of the same name. */}} {{- define "braintrust.apiPoolConfig" -}} {{- $base := deepCopy .root.Values.api -}} {{- $_ := unset $base "workloadIsolation" -}} {{- $overrides := deepCopy (.overrides | default dict) -}} +{{- $baseModuleEnvVars := get $base "moduleEnvVars" | default (list) -}} +{{- $poolModuleEnvVars := get $overrides "moduleEnvVars" | default (list) -}} +{{- $_ := unset $overrides "moduleEnvVars" -}} {{- $baseExtraEnvVars := get $base "extraEnvVars" | default (list) -}} {{- $poolExtraEnvVars := get $overrides "extraEnvVars" | default (list) -}} {{- $_ := unset $overrides "extraEnvVars" -}} {{- $pool := mergeOverwrite $base $overrides -}} +{{- $_ := set $pool "moduleEnvVars" (concat $baseModuleEnvVars $poolModuleEnvVars) -}} {{- $_ := set $pool "extraEnvVars" (concat $baseExtraEnvVars $poolExtraEnvVars) -}} {{- toYaml $pool -}} {{- end -}} @@ -238,6 +245,7 @@ ephemeralStorage: tmpVolume: enabled: false sizeLimit: "" +moduleEnvVars: [] extraEnvVars: [] nodeSelector: {} tolerations: [] diff --git a/braintrust/templates/ai-gateway-deployment.yaml b/braintrust/templates/ai-gateway-deployment.yaml index e78b254..137de23 100644 --- a/braintrust/templates/ai-gateway-deployment.yaml +++ b/braintrust/templates/ai-gateway-deployment.yaml @@ -83,8 +83,11 @@ spec: secretKeyRef: name: braintrust-secrets key: BRAINSTORE_LICENSE_KEY - {{- if .Values.aiGateway.extraEnvVars }} - {{- toYaml .Values.aiGateway.extraEnvVars | nindent 12 }} + {{- with .Values.aiGateway.moduleEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.aiGateway.extraEnvVars }} + {{- toYaml . | nindent 12 }} {{- end }} {{- with .Values.aiGateway.extraContainers }} {{- toYaml . | nindent 8 }} diff --git a/braintrust/templates/api-configmap.yaml b/braintrust/templates/api-configmap.yaml index 42e3672..7705072 100644 --- a/braintrust/templates/api-configmap.yaml +++ b/braintrust/templates/api-configmap.yaml @@ -1,28 +1,22 @@ {{- $orgName := .Values.global.orgName | default "" | toString | trim -}} {{- $primaryOrgName := .Values.global.primaryOrgName | default "" | toString | trim -}} -{{- $hasPrimaryOrgNameExtraEnv := false -}} -{{- range .Values.api.extraEnvVars -}} -{{- if eq (.name | default "" | toString) "PRIMARY_ORG_NAME" -}} -{{- $hasPrimaryOrgNameExtraEnv = true -}} +{{- $apiEnvVars := concat (.Values.api.moduleEnvVars | default (list)) (.Values.api.extraEnvVars | default (list)) -}} +{{- $hasPrimaryOrgNameEnv := false -}} +{{- $hasAwsRegionEnv := false -}} +{{- range $apiEnvVars -}} +{{- $envName := .name | default "" | toString | trim -}} +{{- if eq $envName "PRIMARY_ORG_NAME" -}} +{{- $hasPrimaryOrgNameEnv = true -}} {{- end -}} +{{- if eq $envName "AWS_REGION" -}} +{{- $hasAwsRegionEnv = true -}} {{- end -}} -{{- if and (or (eq $orgName "") (eq $orgName "*")) (eq $primaryOrgName "") (not $hasPrimaryOrgNameExtraEnv) -}} -{{- fail "global.primaryOrgName or api.extraEnvVars PRIMARY_ORG_NAME is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." -}} {{- end -}} -{{- $googleRegion := "" -}} -{{- if eq (.Values.cloud | default "") "google" -}} -{{- $googleRegion = .Values.objectStorage.google.region | default "" | toString | trim -}} -{{- end -}} -{{- if and (eq (.Values.cloud | default "") "google") (not .Values.api.enableGcsAuth) -}} -{{- $hasAwsRegionExtraEnv := false -}} -{{- range .Values.api.extraEnvVars -}} -{{- if eq (.name | default "" | toString) "AWS_REGION" -}} -{{- $hasAwsRegionExtraEnv = true -}} -{{- end -}} -{{- end -}} -{{- if and (eq $googleRegion "") (not $hasAwsRegionExtraEnv) -}} -{{- fail "objectStorage.google.region or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." -}} +{{- if and (or (eq $orgName "") (eq $orgName "*")) (eq $primaryOrgName "") (not $hasPrimaryOrgNameEnv) -}} +{{- fail "global.primaryOrgName or PRIMARY_ORG_NAME in api.moduleEnvVars or api.extraEnvVars is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." -}} {{- end -}} +{{- if and (eq (.Values.cloud | default "") "google") (not .Values.api.enableGcsAuth) (not $hasAwsRegionEnv) -}} +{{- fail "api.moduleEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." -}} {{- end -}} {{- $allowedOrgIds := .Values.global.allowedOrgIds | default "" | toString | trim -}} {{- $btqlStrictOrgIds := .Values.btqlAuditLogsStrictOrgIds | default list -}} @@ -85,10 +79,6 @@ data: AWS_ENDPOINT_URL: "https://storage.googleapis.com" AWS_REQUEST_CHECKSUM_CALCULATION: "WHEN_REQUIRED" AWS_RESPONSE_CHECKSUM_VALIDATION: "WHEN_REQUIRED" - {{- if $googleRegion }} - AWS_REGION: {{ $googleRegion | quote }} - AWS_DEFAULT_REGION: {{ $googleRegion | quote }} - {{- end }} {{- end }} {{- end }} diff --git a/braintrust/templates/brainstore-automationwriter-deployment.yaml b/braintrust/templates/brainstore-automationwriter-deployment.yaml index e8fd45a..b43068a 100644 --- a/braintrust/templates/brainstore-automationwriter-deployment.yaml +++ b/braintrust/templates/brainstore-automationwriter-deployment.yaml @@ -157,8 +157,11 @@ spec: secretKeyRef: name: braintrust-secrets key: FUNCTION_SECRET_KEY - {{- if $aw.extraEnvVars }} - {{- toYaml $aw.extraEnvVars | nindent 12 }} + {{- with $aw.moduleEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with $aw.extraEnvVars }} + {{- toYaml . | nindent 12 }} {{- end }} volumeMounts: - name: cache-volume diff --git a/braintrust/templates/brainstore-fastreader-deployment.yaml b/braintrust/templates/brainstore-fastreader-deployment.yaml index 6ca1d5e..a15c4f7 100644 --- a/braintrust/templates/brainstore-fastreader-deployment.yaml +++ b/braintrust/templates/brainstore-fastreader-deployment.yaml @@ -142,8 +142,11 @@ spec: secretKeyRef: name: braintrust-secrets key: FUNCTION_SECRET_KEY - {{- if .Values.brainstore.fastreader.extraEnvVars }} - {{- toYaml .Values.brainstore.fastreader.extraEnvVars | nindent 12 }} + {{- with .Values.brainstore.fastreader.moduleEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.brainstore.fastreader.extraEnvVars }} + {{- toYaml . | nindent 12 }} {{- end }} volumeMounts: - name: cache-volume diff --git a/braintrust/templates/brainstore-reader-deployment.yaml b/braintrust/templates/brainstore-reader-deployment.yaml index f0342a7..f070962 100644 --- a/braintrust/templates/brainstore-reader-deployment.yaml +++ b/braintrust/templates/brainstore-reader-deployment.yaml @@ -142,8 +142,11 @@ spec: secretKeyRef: name: braintrust-secrets key: FUNCTION_SECRET_KEY - {{- if .Values.brainstore.reader.extraEnvVars }} - {{- toYaml .Values.brainstore.reader.extraEnvVars | nindent 12 }} + {{- with .Values.brainstore.reader.moduleEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.brainstore.reader.extraEnvVars }} + {{- toYaml . | nindent 12 }} {{- end }} volumeMounts: - name: cache-volume diff --git a/braintrust/templates/brainstore-writer-deployment.yaml b/braintrust/templates/brainstore-writer-deployment.yaml index f42b692..63b5694 100644 --- a/braintrust/templates/brainstore-writer-deployment.yaml +++ b/braintrust/templates/brainstore-writer-deployment.yaml @@ -142,8 +142,11 @@ spec: secretKeyRef: name: braintrust-secrets key: FUNCTION_SECRET_KEY - {{- if .Values.brainstore.writer.extraEnvVars }} - {{- toYaml .Values.brainstore.writer.extraEnvVars | nindent 12 }} + {{- with .Values.brainstore.writer.moduleEnvVars }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.brainstore.writer.extraEnvVars }} + {{- toYaml . | nindent 12 }} {{- end }} volumeMounts: - name: cache-volume diff --git a/braintrust/tests/__fixtures__/google-values.yaml b/braintrust/tests/__fixtures__/google-values.yaml index b17263f..70176d8 100644 --- a/braintrust/tests/__fixtures__/google-values.yaml +++ b/braintrust/tests/__fixtures__/google-values.yaml @@ -10,7 +10,11 @@ objectStorage: google: brainstoreBucket: "test-brainstore-bucket" apiBucket: "test-api-bucket" - region: "us-central1" + +api: + extraEnvVars: + - name: AWS_REGION + value: "us-central1" brainstore: serviceAccount: diff --git a/braintrust/tests/api-autoscaling_test.yaml b/braintrust/tests/api-autoscaling_test.yaml index 0d7bbd6..a92f75a 100644 --- a/braintrust/tests/api-autoscaling_test.yaml +++ b/braintrust/tests/api-autoscaling_test.yaml @@ -14,7 +14,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: false release: namespace: "braintrust" @@ -28,7 +30,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: false release: namespace: "braintrust" @@ -55,7 +59,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true release: namespace: "braintrust" @@ -99,7 +105,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true release: namespace: "braintrust" @@ -161,7 +169,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.replicas: 4 release: @@ -189,7 +199,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.extraEnvVars: - name: ENABLE_PROMETHEUS_METRICS @@ -212,7 +224,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: false api.replicas: 4 release: @@ -237,7 +251,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -252,7 +268,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -277,7 +295,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -305,7 +325,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -330,7 +352,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -352,7 +376,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true release: @@ -375,7 +401,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true api.workloadIsolation.ingest.autoscaling.enabled: false @@ -396,7 +424,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true api.workloadIsolation.ingest.autoscaling.enabled: false @@ -412,7 +442,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true api.workloadIsolation.ingest.autoscaling.enabled: false @@ -438,7 +470,9 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - objectStorage.google.region: us-central1 + api.moduleEnvVars: + - name: AWS_REGION + value: us-central1 api.autoscaling.enabled: true api.workloadIsolation.enabled: true api.workloadIsolation.ingest.autoscaling.enabled: false diff --git a/braintrust/tests/api-configmap_test.yaml b/braintrust/tests/api-configmap_test.yaml index fb87f04..95dafd1 100644 --- a/braintrust/tests/api-configmap_test.yaml +++ b/braintrust/tests/api-configmap_test.yaml @@ -122,6 +122,25 @@ tests: path: data.PRIMARY_ORG_NAME value: "primary-org" + - it: should allow wildcard org name when primary org name is provided via module env vars + values: + - __fixtures__/base-values.yaml + set: + global.orgName: "*" + global.primaryOrgName: "" + api.moduleEnvVars: + - name: PRIMARY_ORG_NAME + value: "primary-org" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.ORG_NAME + value: "*" + - equal: + path: data.PRIMARY_ORG_NAME + value: "" + - it: should allow wildcard org name when primary org name is provided via extra env vars values: - __fixtures__/base-values.yaml @@ -151,7 +170,7 @@ tests: namespace: "braintrust" asserts: - failedTemplate: - errorMessage: "global.primaryOrgName or api.extraEnvVars PRIMARY_ORG_NAME is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." + errorMessage: "global.primaryOrgName or PRIMARY_ORG_NAME in api.moduleEnvVars or api.extraEnvVars is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." - it: should reject wildcard org name without primary org name values: @@ -163,7 +182,7 @@ tests: namespace: "braintrust" asserts: - failedTemplate: - errorMessage: "global.primaryOrgName or api.extraEnvVars PRIMARY_ORG_NAME is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." + errorMessage: "global.primaryOrgName or PRIMARY_ORG_NAME in api.moduleEnvVars or api.extraEnvVars is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." - it: should use correct namespace from helper when createNamespace is false values: @@ -262,79 +281,68 @@ tests: - equal: path: data.AWS_RESPONSE_CHECKSUM_VALIDATION value: "WHEN_REQUIRED" - - equal: + - isNull: path: data.AWS_REGION - value: "us-central1" - - equal: - path: data.AWS_DEFAULT_REGION - value: "us-central1" - - it: should keep the GCS region when extraEnvVars replaces the list + - it: should allow a Google HMAC deployment that sets AWS_REGION via extraEnvVars values: - __fixtures__/base-values.yaml - __fixtures__/google-values.yaml set: + api.moduleEnvVars: [] api.extraEnvVars: - - name: ENABLE_CONTAINER_CPU_METRICS - value: "true" + - name: AWS_REGION + value: "us-central1" release: namespace: "braintrust" asserts: - equal: - path: data.AWS_REGION - value: "us-central1" - - equal: - path: data.AWS_DEFAULT_REGION - value: "us-central1" + path: data.AWS_ENDPOINT_URL + value: "https://storage.googleapis.com" - - it: should trim the GCS region + - it: should allow a Google HMAC deployment that sets AWS_REGION via moduleEnvVars values: - __fixtures__/base-values.yaml - __fixtures__/google-values.yaml set: - objectStorage.google.region: " us-central1 " + api.extraEnvVars: [] + api.moduleEnvVars: + - name: AWS_REGION + value: "us-central1" release: namespace: "braintrust" asserts: - equal: - path: data.AWS_REGION - value: "us-central1" - - equal: - path: data.AWS_DEFAULT_REGION - value: "us-central1" + path: data.AWS_ENDPOINT_URL + value: "https://storage.googleapis.com" - - it: should allow a Google HMAC deployment that sets AWS_REGION via extraEnvVars + - it: should reject a Google HMAC deployment with no AWS_REGION values: - __fixtures__/base-values.yaml - __fixtures__/google-values.yaml set: - objectStorage.google.region: "" - api.extraEnvVars: - - name: AWS_REGION - value: "us-central1" + api.moduleEnvVars: [] + api.extraEnvVars: [] release: namespace: "braintrust" asserts: - - equal: - path: data.AWS_ENDPOINT_URL - value: "https://storage.googleapis.com" - - isNull: - path: data.AWS_REGION - - isNull: - path: data.AWS_DEFAULT_REGION + - failedTemplate: + errorMessage: "api.moduleEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." - - it: should reject a Google HMAC deployment with no region + - it: should reject a whitespace-only env name as AWS_REGION values: - __fixtures__/base-values.yaml - __fixtures__/google-values.yaml set: - objectStorage.google.region: "" api.extraEnvVars: [] + api.moduleEnvVars: + - name: " " + value: "us-central1" release: namespace: "braintrust" asserts: - failedTemplate: - errorMessage: "objectStorage.google.region or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." + errorMessage: "api.moduleEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." - it: should not set checksum vars when enableGcsAuth is true values: @@ -367,7 +375,8 @@ tests: set: api.enableGcsAuth: true api.serviceAccount.googleServiceAccount: "test@project.iam.gserviceaccount.com" - objectStorage.google.region: "" + api.moduleEnvVars: [] + api.extraEnvVars: [] release: namespace: "braintrust" asserts: diff --git a/braintrust/tests/api-workload-isolation_test.yaml b/braintrust/tests/api-workload-isolation_test.yaml index 6464553..ab4413d 100644 --- a/braintrust/tests/api-workload-isolation_test.yaml +++ b/braintrust/tests/api-workload-isolation_test.yaml @@ -102,6 +102,157 @@ tests: name: POOL_SETTING value: background + - it: should keep moduleEnvVars when extraEnvVars is overridden on every API pool + template: api-deployment.yaml + values: + - __fixtures__/base-values.yaml + set: + api.workloadIsolation.enabled: true + api.moduleEnvVars: + - name: AWS_REGION + value: from-module + - name: SHARED_NAME + value: module-value + api.extraEnvVars: + - name: USER_ONLY + value: from-user + - name: SHARED_NAME + value: user-value + api.workloadIsolation.ingest.moduleEnvVars: + - name: INGEST_MODULE + value: ingest + api.workloadIsolation.background.extraEnvVars: + - name: BACKGROUND_USER + value: background + documentIndex: 0 + asserts: + - equal: + path: spec.template.spec.containers[0].env[-4].name + value: AWS_REGION + - equal: + path: spec.template.spec.containers[0].env[-4].value + value: from-module + - equal: + path: spec.template.spec.containers[0].env[-3].name + value: SHARED_NAME + - equal: + path: spec.template.spec.containers[0].env[-3].value + value: module-value + - equal: + path: spec.template.spec.containers[0].env[-2].name + value: USER_ONLY + - equal: + path: spec.template.spec.containers[0].env[-2].value + value: from-user + - equal: + path: spec.template.spec.containers[0].env[-1].name + value: SHARED_NAME + - equal: + path: spec.template.spec.containers[0].env[-1].value + value: user-value + - notContains: + path: spec.template.spec.containers[0].env + content: + name: INGEST_MODULE + value: ingest + - notContains: + path: spec.template.spec.containers[0].env + content: + name: BACKGROUND_USER + value: background + + - it: should append ingest moduleEnvVars after the shared module list + template: api-deployment.yaml + values: + - __fixtures__/base-values.yaml + set: + api.workloadIsolation.enabled: true + api.moduleEnvVars: + - name: AWS_REGION + value: from-module + api.extraEnvVars: + - name: USER_ONLY + value: from-user + api.workloadIsolation.ingest.moduleEnvVars: + - name: INGEST_MODULE + value: ingest + documentIndex: 1 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: AWS_REGION + value: from-module + - contains: + path: spec.template.spec.containers[0].env + content: + name: INGEST_MODULE + value: ingest + - equal: + path: spec.template.spec.containers[0].env[-3].name + value: AWS_REGION + - equal: + path: spec.template.spec.containers[0].env[-3].value + value: from-module + - equal: + path: spec.template.spec.containers[0].env[-2].name + value: INGEST_MODULE + - equal: + path: spec.template.spec.containers[0].env[-2].value + value: ingest + - equal: + path: spec.template.spec.containers[0].env[-1].name + value: USER_ONLY + - equal: + path: spec.template.spec.containers[0].env[-1].value + value: from-user + + - it: should append background extraEnvVars after shared moduleEnvVars and extraEnvVars + template: api-deployment.yaml + values: + - __fixtures__/base-values.yaml + set: + api.workloadIsolation.enabled: true + api.moduleEnvVars: + - name: AWS_REGION + value: from-module + api.extraEnvVars: + - name: USER_ONLY + value: from-user + api.workloadIsolation.background.extraEnvVars: + - name: BACKGROUND_USER + value: background + documentIndex: 2 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: AWS_REGION + value: from-module + - contains: + path: spec.template.spec.containers[0].env + content: + name: USER_ONLY + value: from-user + - equal: + path: spec.template.spec.containers[0].env[-3].name + value: AWS_REGION + - equal: + path: spec.template.spec.containers[0].env[-3].value + value: from-module + - equal: + path: spec.template.spec.containers[0].env[-2].name + value: USER_ONLY + - equal: + path: spec.template.spec.containers[0].env[-2].value + value: from-user + - equal: + path: spec.template.spec.containers[0].env[-1].name + value: BACKGROUND_USER + - equal: + path: spec.template.spec.containers[0].env[-1].value + value: background + - it: should render an isolated ingest Service with inherited annotations template: api-service.yaml values: diff --git a/braintrust/tests/brainstore-writer_test.yaml b/braintrust/tests/brainstore-writer_test.yaml index d2af988..c150f06 100644 --- a/braintrust/tests/brainstore-writer_test.yaml +++ b/braintrust/tests/brainstore-writer_test.yaml @@ -318,6 +318,49 @@ tests: name: CUSTOM_VAR value: "custom-value" + - it: should render moduleEnvVars before extraEnvVars so the user value wins + template: brainstore-writer-deployment.yaml + values: + - __fixtures__/base-values.yaml + set: + brainstore.writer.moduleEnvVars: + - name: MODULE_VAR + value: from-module + - name: SHARED_NAME + value: module-value + brainstore.writer.extraEnvVars: + - name: USER_VAR + value: from-user + - name: SHARED_NAME + value: user-value + release: + namespace: "braintrust" + asserts: + - equal: + path: spec.template.spec.containers[0].env[-4].name + value: MODULE_VAR + - equal: + path: spec.template.spec.containers[0].env[-4].value + value: from-module + - equal: + path: spec.template.spec.containers[0].env[-3].name + value: SHARED_NAME + - equal: + path: spec.template.spec.containers[0].env[-3].value + value: module-value + - equal: + path: spec.template.spec.containers[0].env[-2].name + value: USER_VAR + - equal: + path: spec.template.spec.containers[0].env[-2].value + value: from-user + - equal: + path: spec.template.spec.containers[0].env[-1].name + value: SHARED_NAME + - equal: + path: spec.template.spec.containers[0].env[-1].value + value: user-value + - it: should include livenessProbe when configured template: brainstore-writer-deployment.yaml values: diff --git a/braintrust/values.yaml b/braintrust/values.yaml index 299dc19..9b2c602 100644 --- a/braintrust/values.yaml +++ b/braintrust/values.yaml @@ -2,7 +2,7 @@ global: orgName: "" # Required when orgName is empty or "*" unless PRIMARY_ORG_NAME is supplied - # via api.extraEnvVars. Used to authorize self-hosted service-token management. + # via api.moduleEnvVars or api.extraEnvVars. Used to authorize self-hosted service-token management. primaryOrgName: "" # Optional comma-separated Braintrust Org ID allowlist (IDs, not org names). # Do not include spaces. If orgName is a specific name, that org is included @@ -74,11 +74,6 @@ objectStorage: brainstoreBucket: "" # Single API bucket with paths for responses and code bundles apiBucket: "" - # GCS bucket region. Required for S3-compatible HMAC access - # (api.enableGcsAuth false). Rendered as AWS_REGION and - # AWS_DEFAULT_REGION on the API. api.extraEnvVars can still override - # AWS_REGION, but replacing that list does not remove this value. - region: "" # No-PG mode: controls which object types bypass PostgreSQL and use Brainstore directly. # Options: @@ -278,6 +273,9 @@ api: # validation may allow even if private or reserved. Hard-blocked metadata, # link-local, multicast, unspecified, and future-use ranges remain blocked. urlSecurityAllowCidrs: "" + # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. + # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. + moduleEnvVars: [] extraEnvVars: # Example: # - name: MY_ENV_VAR @@ -369,6 +367,9 @@ aiGateway: timeoutSeconds: 5 failureThreshold: 3 successThreshold: 1 + # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. + # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. + moduleEnvVars: [] extraEnvVars: [] nodeSelector: {} tolerations: [] @@ -472,6 +473,9 @@ brainstore: tmpVolume: enabled: false sizeLimit: "" + # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. + # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. + moduleEnvVars: [] extraEnvVars: [] nodeSelector: {} tolerations: [] @@ -530,6 +534,9 @@ brainstore: tmpVolume: enabled: false sizeLimit: "" + # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. + # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. + moduleEnvVars: [] extraEnvVars: [] nodeSelector: {} tolerations: [] @@ -589,6 +596,9 @@ brainstore: tmpVolume: enabled: false sizeLimit: "" + # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. + # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. + moduleEnvVars: [] extraEnvVars: [] # Example: # - name: MY_ENV_VAR @@ -665,6 +675,9 @@ brainstore: tmpVolume: enabled: false sizeLimit: "" + # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. + # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. + moduleEnvVars: [] extraEnvVars: [] # Example: # - name: MY_ENV_VAR From 808313e39ef74bd40aae39c9574ebe3c9b821cd2 Mon Sep 17 00:00:00 2001 From: Erik Weathers <1111441+erikdw@users.noreply.github.com> Date: Tue, 20 Oct 2026 22:22:07 -0700 Subject: [PATCH 3/4] Rename moduleEnvVars to platformEnvVars. The list is reserved for the installer. Hand-edited values stay in extraEnvVars, which is still rendered after the platform list so a user entry overrides the same name. Co-authored-by: Cursor --- braintrust/templates/_api-deployment.tpl | 2 +- braintrust/templates/_helpers.tpl | 16 ++++---- .../templates/ai-gateway-deployment.yaml | 2 +- braintrust/templates/api-configmap.yaml | 6 +-- ...rainstore-automationwriter-deployment.yaml | 2 +- .../brainstore-fastreader-deployment.yaml | 2 +- .../brainstore-reader-deployment.yaml | 2 +- .../brainstore-writer-deployment.yaml | 2 +- braintrust/tests/api-autoscaling_test.yaml | 34 ++++++++--------- braintrust/tests/api-configmap_test.yaml | 22 +++++------ .../tests/api-workload-isolation_test.yaml | 16 ++++---- braintrust/tests/brainstore-writer_test.yaml | 4 +- braintrust/values.yaml | 38 +++++++++---------- 13 files changed, 74 insertions(+), 74 deletions(-) diff --git a/braintrust/templates/_api-deployment.tpl b/braintrust/templates/_api-deployment.tpl index 7f639d7..5942533 100644 --- a/braintrust/templates/_api-deployment.tpl +++ b/braintrust/templates/_api-deployment.tpl @@ -231,7 +231,7 @@ spec: - name: PIP_CERT value: {{ $customCAPath | quote }} {{- end }} - {{- with $api.moduleEnvVars }} + {{- with $api.platformEnvVars }} {{- toYaml . | nindent 12 }} {{- end }} {{- with $api.extraEnvVars }} diff --git a/braintrust/templates/_helpers.tpl b/braintrust/templates/_helpers.tpl index d283a83..a8282bb 100644 --- a/braintrust/templates/_helpers.tpl +++ b/braintrust/templates/_helpers.tpl @@ -65,23 +65,23 @@ http://{{ .Values.api.service.name | default .Values.api.name }}.{{ include "bra {{/* Build one API pool from the shared api values plus pool-specific overrides. -Pool moduleEnvVars and extraEnvVars are appended so shared provider -configuration is retained. moduleEnvVars stay ahead of extraEnvVars. +Pool platformEnvVars and extraEnvVars are appended so shared provider +configuration is retained. platformEnvVars stay ahead of extraEnvVars. The kubelet keeps the last duplicate env name, so a user extraEnvVars -entry overrides a moduleEnvVars entry of the same name. +entry overrides a platformEnvVars entry of the same name. */}} {{- define "braintrust.apiPoolConfig" -}} {{- $base := deepCopy .root.Values.api -}} {{- $_ := unset $base "workloadIsolation" -}} {{- $overrides := deepCopy (.overrides | default dict) -}} -{{- $baseModuleEnvVars := get $base "moduleEnvVars" | default (list) -}} -{{- $poolModuleEnvVars := get $overrides "moduleEnvVars" | default (list) -}} -{{- $_ := unset $overrides "moduleEnvVars" -}} +{{- $basePlatformEnvVars := get $base "platformEnvVars" | default (list) -}} +{{- $poolPlatformEnvVars := get $overrides "platformEnvVars" | default (list) -}} +{{- $_ := unset $overrides "platformEnvVars" -}} {{- $baseExtraEnvVars := get $base "extraEnvVars" | default (list) -}} {{- $poolExtraEnvVars := get $overrides "extraEnvVars" | default (list) -}} {{- $_ := unset $overrides "extraEnvVars" -}} {{- $pool := mergeOverwrite $base $overrides -}} -{{- $_ := set $pool "moduleEnvVars" (concat $baseModuleEnvVars $poolModuleEnvVars) -}} +{{- $_ := set $pool "platformEnvVars" (concat $basePlatformEnvVars $poolPlatformEnvVars) -}} {{- $_ := set $pool "extraEnvVars" (concat $baseExtraEnvVars $poolExtraEnvVars) -}} {{- toYaml $pool -}} {{- end -}} @@ -245,7 +245,7 @@ ephemeralStorage: tmpVolume: enabled: false sizeLimit: "" -moduleEnvVars: [] +platformEnvVars: [] extraEnvVars: [] nodeSelector: {} tolerations: [] diff --git a/braintrust/templates/ai-gateway-deployment.yaml b/braintrust/templates/ai-gateway-deployment.yaml index 137de23..6ba995c 100644 --- a/braintrust/templates/ai-gateway-deployment.yaml +++ b/braintrust/templates/ai-gateway-deployment.yaml @@ -83,7 +83,7 @@ spec: secretKeyRef: name: braintrust-secrets key: BRAINSTORE_LICENSE_KEY - {{- with .Values.aiGateway.moduleEnvVars }} + {{- with .Values.aiGateway.platformEnvVars }} {{- toYaml . | nindent 12 }} {{- end }} {{- with .Values.aiGateway.extraEnvVars }} diff --git a/braintrust/templates/api-configmap.yaml b/braintrust/templates/api-configmap.yaml index 7705072..76ef69d 100644 --- a/braintrust/templates/api-configmap.yaml +++ b/braintrust/templates/api-configmap.yaml @@ -1,6 +1,6 @@ {{- $orgName := .Values.global.orgName | default "" | toString | trim -}} {{- $primaryOrgName := .Values.global.primaryOrgName | default "" | toString | trim -}} -{{- $apiEnvVars := concat (.Values.api.moduleEnvVars | default (list)) (.Values.api.extraEnvVars | default (list)) -}} +{{- $apiEnvVars := concat (.Values.api.platformEnvVars | default (list)) (.Values.api.extraEnvVars | default (list)) -}} {{- $hasPrimaryOrgNameEnv := false -}} {{- $hasAwsRegionEnv := false -}} {{- range $apiEnvVars -}} @@ -13,10 +13,10 @@ {{- end -}} {{- end -}} {{- if and (or (eq $orgName "") (eq $orgName "*")) (eq $primaryOrgName "") (not $hasPrimaryOrgNameEnv) -}} -{{- fail "global.primaryOrgName or PRIMARY_ORG_NAME in api.moduleEnvVars or api.extraEnvVars is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." -}} +{{- fail "global.primaryOrgName or PRIMARY_ORG_NAME in api.platformEnvVars or api.extraEnvVars is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." -}} {{- end -}} {{- if and (eq (.Values.cloud | default "") "google") (not .Values.api.enableGcsAuth) (not $hasAwsRegionEnv) -}} -{{- fail "api.moduleEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." -}} +{{- fail "api.platformEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." -}} {{- end -}} {{- $allowedOrgIds := .Values.global.allowedOrgIds | default "" | toString | trim -}} {{- $btqlStrictOrgIds := .Values.btqlAuditLogsStrictOrgIds | default list -}} diff --git a/braintrust/templates/brainstore-automationwriter-deployment.yaml b/braintrust/templates/brainstore-automationwriter-deployment.yaml index b43068a..7133ebb 100644 --- a/braintrust/templates/brainstore-automationwriter-deployment.yaml +++ b/braintrust/templates/brainstore-automationwriter-deployment.yaml @@ -157,7 +157,7 @@ spec: secretKeyRef: name: braintrust-secrets key: FUNCTION_SECRET_KEY - {{- with $aw.moduleEnvVars }} + {{- with $aw.platformEnvVars }} {{- toYaml . | nindent 12 }} {{- end }} {{- with $aw.extraEnvVars }} diff --git a/braintrust/templates/brainstore-fastreader-deployment.yaml b/braintrust/templates/brainstore-fastreader-deployment.yaml index a15c4f7..9ed567c 100644 --- a/braintrust/templates/brainstore-fastreader-deployment.yaml +++ b/braintrust/templates/brainstore-fastreader-deployment.yaml @@ -142,7 +142,7 @@ spec: secretKeyRef: name: braintrust-secrets key: FUNCTION_SECRET_KEY - {{- with .Values.brainstore.fastreader.moduleEnvVars }} + {{- with .Values.brainstore.fastreader.platformEnvVars }} {{- toYaml . | nindent 12 }} {{- end }} {{- with .Values.brainstore.fastreader.extraEnvVars }} diff --git a/braintrust/templates/brainstore-reader-deployment.yaml b/braintrust/templates/brainstore-reader-deployment.yaml index f070962..bf5d08a 100644 --- a/braintrust/templates/brainstore-reader-deployment.yaml +++ b/braintrust/templates/brainstore-reader-deployment.yaml @@ -142,7 +142,7 @@ spec: secretKeyRef: name: braintrust-secrets key: FUNCTION_SECRET_KEY - {{- with .Values.brainstore.reader.moduleEnvVars }} + {{- with .Values.brainstore.reader.platformEnvVars }} {{- toYaml . | nindent 12 }} {{- end }} {{- with .Values.brainstore.reader.extraEnvVars }} diff --git a/braintrust/templates/brainstore-writer-deployment.yaml b/braintrust/templates/brainstore-writer-deployment.yaml index 63b5694..ef1a846 100644 --- a/braintrust/templates/brainstore-writer-deployment.yaml +++ b/braintrust/templates/brainstore-writer-deployment.yaml @@ -142,7 +142,7 @@ spec: secretKeyRef: name: braintrust-secrets key: FUNCTION_SECRET_KEY - {{- with .Values.brainstore.writer.moduleEnvVars }} + {{- with .Values.brainstore.writer.platformEnvVars }} {{- toYaml . | nindent 12 }} {{- end }} {{- with .Values.brainstore.writer.extraEnvVars }} diff --git a/braintrust/tests/api-autoscaling_test.yaml b/braintrust/tests/api-autoscaling_test.yaml index a92f75a..adcefc6 100644 --- a/braintrust/tests/api-autoscaling_test.yaml +++ b/braintrust/tests/api-autoscaling_test.yaml @@ -14,7 +14,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: false @@ -30,7 +30,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: false @@ -59,7 +59,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -105,7 +105,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -169,7 +169,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -199,7 +199,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -224,7 +224,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: false @@ -251,7 +251,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -268,7 +268,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -295,7 +295,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -325,7 +325,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -352,7 +352,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -376,7 +376,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -401,7 +401,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -424,7 +424,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -442,7 +442,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true @@ -470,7 +470,7 @@ tests: - __fixtures__/base-values.yaml set: cloud: google - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: us-central1 api.autoscaling.enabled: true diff --git a/braintrust/tests/api-configmap_test.yaml b/braintrust/tests/api-configmap_test.yaml index 95dafd1..9555e53 100644 --- a/braintrust/tests/api-configmap_test.yaml +++ b/braintrust/tests/api-configmap_test.yaml @@ -128,7 +128,7 @@ tests: set: global.orgName: "*" global.primaryOrgName: "" - api.moduleEnvVars: + api.platformEnvVars: - name: PRIMARY_ORG_NAME value: "primary-org" release: @@ -170,7 +170,7 @@ tests: namespace: "braintrust" asserts: - failedTemplate: - errorMessage: "global.primaryOrgName or PRIMARY_ORG_NAME in api.moduleEnvVars or api.extraEnvVars is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." + errorMessage: "global.primaryOrgName or PRIMARY_ORG_NAME in api.platformEnvVars or api.extraEnvVars is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." - it: should reject wildcard org name without primary org name values: @@ -182,7 +182,7 @@ tests: namespace: "braintrust" asserts: - failedTemplate: - errorMessage: "global.primaryOrgName or PRIMARY_ORG_NAME in api.moduleEnvVars or api.extraEnvVars is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." + errorMessage: "global.primaryOrgName or PRIMARY_ORG_NAME in api.platformEnvVars or api.extraEnvVars is required when global.orgName is empty or \"*\"; self-hosted service-token management needs a primary organization." - it: should use correct namespace from helper when createNamespace is false values: @@ -289,7 +289,7 @@ tests: - __fixtures__/base-values.yaml - __fixtures__/google-values.yaml set: - api.moduleEnvVars: [] + api.platformEnvVars: [] api.extraEnvVars: - name: AWS_REGION value: "us-central1" @@ -300,13 +300,13 @@ tests: path: data.AWS_ENDPOINT_URL value: "https://storage.googleapis.com" - - it: should allow a Google HMAC deployment that sets AWS_REGION via moduleEnvVars + - it: should allow a Google HMAC deployment that sets AWS_REGION via platformEnvVars values: - __fixtures__/base-values.yaml - __fixtures__/google-values.yaml set: api.extraEnvVars: [] - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: "us-central1" release: @@ -321,13 +321,13 @@ tests: - __fixtures__/base-values.yaml - __fixtures__/google-values.yaml set: - api.moduleEnvVars: [] + api.platformEnvVars: [] api.extraEnvVars: [] release: namespace: "braintrust" asserts: - failedTemplate: - errorMessage: "api.moduleEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." + errorMessage: "api.platformEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." - it: should reject a whitespace-only env name as AWS_REGION values: @@ -335,14 +335,14 @@ tests: - __fixtures__/google-values.yaml set: api.extraEnvVars: [] - api.moduleEnvVars: + api.platformEnvVars: - name: " " value: "us-central1" release: namespace: "braintrust" asserts: - failedTemplate: - errorMessage: "api.moduleEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." + errorMessage: "api.platformEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." - it: should not set checksum vars when enableGcsAuth is true values: @@ -375,7 +375,7 @@ tests: set: api.enableGcsAuth: true api.serviceAccount.googleServiceAccount: "test@project.iam.gserviceaccount.com" - api.moduleEnvVars: [] + api.platformEnvVars: [] api.extraEnvVars: [] release: namespace: "braintrust" diff --git a/braintrust/tests/api-workload-isolation_test.yaml b/braintrust/tests/api-workload-isolation_test.yaml index ab4413d..b3ff0cf 100644 --- a/braintrust/tests/api-workload-isolation_test.yaml +++ b/braintrust/tests/api-workload-isolation_test.yaml @@ -102,13 +102,13 @@ tests: name: POOL_SETTING value: background - - it: should keep moduleEnvVars when extraEnvVars is overridden on every API pool + - it: should keep platformEnvVars when extraEnvVars is overridden on every API pool template: api-deployment.yaml values: - __fixtures__/base-values.yaml set: api.workloadIsolation.enabled: true - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: from-module - name: SHARED_NAME @@ -118,7 +118,7 @@ tests: value: from-user - name: SHARED_NAME value: user-value - api.workloadIsolation.ingest.moduleEnvVars: + api.workloadIsolation.ingest.platformEnvVars: - name: INGEST_MODULE value: ingest api.workloadIsolation.background.extraEnvVars: @@ -161,19 +161,19 @@ tests: name: BACKGROUND_USER value: background - - it: should append ingest moduleEnvVars after the shared module list + - it: should append ingest platformEnvVars after the shared platform list template: api-deployment.yaml values: - __fixtures__/base-values.yaml set: api.workloadIsolation.enabled: true - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: from-module api.extraEnvVars: - name: USER_ONLY value: from-user - api.workloadIsolation.ingest.moduleEnvVars: + api.workloadIsolation.ingest.platformEnvVars: - name: INGEST_MODULE value: ingest documentIndex: 1 @@ -207,13 +207,13 @@ tests: path: spec.template.spec.containers[0].env[-1].value value: from-user - - it: should append background extraEnvVars after shared moduleEnvVars and extraEnvVars + - it: should append background extraEnvVars after shared platformEnvVars and extraEnvVars template: api-deployment.yaml values: - __fixtures__/base-values.yaml set: api.workloadIsolation.enabled: true - api.moduleEnvVars: + api.platformEnvVars: - name: AWS_REGION value: from-module api.extraEnvVars: diff --git a/braintrust/tests/brainstore-writer_test.yaml b/braintrust/tests/brainstore-writer_test.yaml index c150f06..4521d97 100644 --- a/braintrust/tests/brainstore-writer_test.yaml +++ b/braintrust/tests/brainstore-writer_test.yaml @@ -318,12 +318,12 @@ tests: name: CUSTOM_VAR value: "custom-value" - - it: should render moduleEnvVars before extraEnvVars so the user value wins + - it: should render platformEnvVars before extraEnvVars so the user value wins template: brainstore-writer-deployment.yaml values: - __fixtures__/base-values.yaml set: - brainstore.writer.moduleEnvVars: + brainstore.writer.platformEnvVars: - name: MODULE_VAR value: from-module - name: SHARED_NAME diff --git a/braintrust/values.yaml b/braintrust/values.yaml index 9b2c602..628c20c 100644 --- a/braintrust/values.yaml +++ b/braintrust/values.yaml @@ -2,7 +2,7 @@ global: orgName: "" # Required when orgName is empty or "*" unless PRIMARY_ORG_NAME is supplied - # via api.moduleEnvVars or api.extraEnvVars. Used to authorize self-hosted service-token management. + # via api.platformEnvVars or api.extraEnvVars. Used to authorize self-hosted service-token management. primaryOrgName: "" # Optional comma-separated Braintrust Org ID allowlist (IDs, not org names). # Do not include spaces. If orgName is a specific name, that org is included @@ -273,9 +273,9 @@ api: # validation may allow even if private or reserved. Hard-blocked metadata, # link-local, multicast, unspecified, and future-use ranges remain blocked. urlSecurityAllowCidrs: "" - # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. - # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. - moduleEnvVars: [] + # Reserved for the installer (the Terraform module). Hand-edited values belong in extraEnvVars. + # Setting platformEnvVars by hand replaces the platform list. + platformEnvVars: [] extraEnvVars: # Example: # - name: MY_ENV_VAR @@ -367,9 +367,9 @@ aiGateway: timeoutSeconds: 5 failureThreshold: 3 successThreshold: 1 - # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. - # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. - moduleEnvVars: [] + # Reserved for the installer (the Terraform module). Hand-edited values belong in extraEnvVars. + # Setting platformEnvVars by hand replaces the platform list. + platformEnvVars: [] extraEnvVars: [] nodeSelector: {} tolerations: [] @@ -473,9 +473,9 @@ brainstore: tmpVolume: enabled: false sizeLimit: "" - # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. - # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. - moduleEnvVars: [] + # Reserved for the installer (the Terraform module). Hand-edited values belong in extraEnvVars. + # Setting platformEnvVars by hand replaces the platform list. + platformEnvVars: [] extraEnvVars: [] nodeSelector: {} tolerations: [] @@ -534,9 +534,9 @@ brainstore: tmpVolume: enabled: false sizeLimit: "" - # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. - # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. - moduleEnvVars: [] + # Reserved for the installer (the Terraform module). Hand-edited values belong in extraEnvVars. + # Setting platformEnvVars by hand replaces the platform list. + platformEnvVars: [] extraEnvVars: [] nodeSelector: {} tolerations: [] @@ -596,9 +596,9 @@ brainstore: tmpVolume: enabled: false sizeLimit: "" - # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. - # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. - moduleEnvVars: [] + # Reserved for the installer (the Terraform module). Hand-edited values belong in extraEnvVars. + # Setting platformEnvVars by hand replaces the platform list. + platformEnvVars: [] extraEnvVars: [] # Example: # - name: MY_ENV_VAR @@ -675,9 +675,9 @@ brainstore: tmpVolume: enabled: false sizeLimit: "" - # Reserved for Terraform modules. Hand-edited values belong in extraEnvVars. - # Setting moduleEnvVars by hand replaces the module list and brings the footgun back. - moduleEnvVars: [] + # Reserved for the installer (the Terraform module). Hand-edited values belong in extraEnvVars. + # Setting platformEnvVars by hand replaces the platform list. + platformEnvVars: [] extraEnvVars: [] # Example: # - name: MY_ENV_VAR From ab3ca6e5a9e9d8c10af13616bb340aaebbf92a8e Mon Sep 17 00:00:00 2001 From: Erik Weathers <1111441+erikdw@users.noreply.github.com> Date: Wed, 21 Oct 2026 14:46:40 -0700 Subject: [PATCH 4/4] Reject a blank AWS_REGION when checking Google HMAC renders. A name-only or empty literal entry was enough to pass the guard, so the API could still deploy without a usable region. A valueFrom reference still counts, and a later entry replaces an earlier one. Co-authored-by: Cursor --- braintrust/templates/api-configmap.yaml | 7 ++ braintrust/tests/api-configmap_test.yaml | 98 ++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/braintrust/templates/api-configmap.yaml b/braintrust/templates/api-configmap.yaml index 76ef69d..c23748e 100644 --- a/braintrust/templates/api-configmap.yaml +++ b/braintrust/templates/api-configmap.yaml @@ -9,7 +9,14 @@ {{- $hasPrimaryOrgNameEnv = true -}} {{- end -}} {{- if eq $envName "AWS_REGION" -}} +{{- /* Last duplicate wins, matching kubelet env precedence. A later blank literal clears an earlier region. valueFrom is accepted without inspecting the secret. */ -}} +{{- if .valueFrom -}} {{- $hasAwsRegionEnv = true -}} +{{- else if ne (.value | default "" | toString | trim) "" -}} +{{- $hasAwsRegionEnv = true -}} +{{- else -}} +{{- $hasAwsRegionEnv = false -}} +{{- end -}} {{- end -}} {{- end -}} {{- if and (or (eq $orgName "") (eq $orgName "*")) (eq $primaryOrgName "") (not $hasPrimaryOrgNameEnv) -}} diff --git a/braintrust/tests/api-configmap_test.yaml b/braintrust/tests/api-configmap_test.yaml index 9555e53..16895ef 100644 --- a/braintrust/tests/api-configmap_test.yaml +++ b/braintrust/tests/api-configmap_test.yaml @@ -329,6 +329,104 @@ tests: - failedTemplate: errorMessage: "api.platformEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." + - it: should reject a blank AWS_REGION literal in extraEnvVars + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + api.platformEnvVars: [] + api.extraEnvVars: + - name: AWS_REGION + value: "" + release: + namespace: "braintrust" + asserts: + - failedTemplate: + errorMessage: "api.platformEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." + + - it: should reject a name-only AWS_REGION entry + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + api.platformEnvVars: [] + api.extraEnvVars: + - name: AWS_REGION + release: + namespace: "braintrust" + asserts: + - failedTemplate: + errorMessage: "api.platformEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." + + - it: should reject a whitespace-only AWS_REGION value + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + api.extraEnvVars: [] + api.platformEnvVars: + - name: AWS_REGION + value: " " + release: + namespace: "braintrust" + asserts: + - failedTemplate: + errorMessage: "api.platformEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." + + - it: should reject a later blank AWS_REGION that overrides a real one + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + api.platformEnvVars: + - name: AWS_REGION + value: "us-central1" + api.extraEnvVars: + - name: AWS_REGION + value: "" + release: + namespace: "braintrust" + asserts: + - failedTemplate: + errorMessage: "api.platformEnvVars or api.extraEnvVars AWS_REGION is required when cloud is google and api.enableGcsAuth is false; S3-compatible GCS needs a region." + + - it: should allow AWS_REGION from valueFrom without a literal value + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + api.platformEnvVars: [] + api.extraEnvVars: + - name: AWS_REGION + valueFrom: + secretKeyRef: + name: braintrust-secrets + key: AWS_REGION + release: + namespace: "braintrust" + asserts: + - equal: + path: data.AWS_ENDPOINT_URL + value: "https://storage.googleapis.com" + + - it: should let a later literal AWS_REGION replace a blank platform entry + values: + - __fixtures__/base-values.yaml + - __fixtures__/google-values.yaml + set: + api.platformEnvVars: + - name: AWS_REGION + value: "" + api.extraEnvVars: + - name: AWS_REGION + value: "us-central1" + release: + namespace: "braintrust" + asserts: + - equal: + path: data.AWS_ENDPOINT_URL + value: "https://storage.googleapis.com" + - it: should reject a whitespace-only env name as AWS_REGION values: - __fixtures__/base-values.yaml