diff --git a/packaging/helm/openwork-ee/README.md b/packaging/helm/openwork-ee/README.md index 66a2f41b97..ece68f99fa 100644 --- a/packaging/helm/openwork-ee/README.md +++ b/packaging/helm/openwork-ee/README.md @@ -350,19 +350,24 @@ externalSecrets: name: external-secrets kind: ClusterSecretStore refreshInterval: 5m - # Every secret.keys.* value must exist as a JSON property under this trunk, - # e.g. eks/openwork/prod/den/DATABASE_URL. + # The three boot-critical keys must exist under this trunk, e.g. + # eks/openwork/prod/den/DATABASE_URL. All other keys are optional. pathPrefix: "eks/openwork/prod/den" ``` -Every property the workloads consume must exist in your provider under -`pathPrefix`, named like `secret.keys.*` values (`DATABASE_URL`, -`BETTER_AUTH_SECRET`, ...) — the chart pulls each key by name and cannot -invent missing ones. `target.deletionPolicy` defaults to `Retain`, so -uninstalling the release keeps the materialized Secret. ESO must be installed -on the destination cluster with a `SecretStore`/`ClusterSecretStore`; the -chart selects `external-secrets.io/v1` or `v1beta1` from cluster capabilities -and fails loudly at sync time if the CRDs are missing. +Only three keys must exist in your provider under `pathPrefix`: +`DATABASE_URL`, `BETTER_AUTH_SECRET`, and `DEN_DB_ENCRYPTION_KEY` — without +them the workloads cannot start, so their `remoteRef`s are required and a +missing one fails the ExternalSecret loudly. Every other `secret.keys.*` entry +is rendered `optional: true` (requires ESO ≥ 0.5.3), so a missing optional key +(`DAYTONA_API_KEY`, `SMTP_PASS`, ...) does not block the Secret — ESO skips it +and the app reads it as unset. Key names must match `secret.keys.*` values; +the chart pulls each by name and cannot rename. `target.deletionPolicy` +defaults to `Retain`, so uninstalling the release keeps the materialized +Secret. ESO must be installed on the destination cluster with a +`SecretStore`/`ClusterSecretStore`; the chart selects `external-secrets.io/v1` +or `v1beta1` from cluster capabilities and fails loudly at sync time if the +CRDs are missing. Set optional `DATABASE_REDIS_URL` to enable Den API Redis-backed session and query caching. Set `DAYTONA_API_KEY` when `config.provisioner.mode` is `daytona`. Set `POLAR_ACCESS_TOKEN` when Polar feature gating is enabled. Set `OPENROUTER_MANAGEMENT_API_KEY` when enabling OpenWork Models management. diff --git a/packaging/helm/openwork-ee/templates/externalsecret.yaml b/packaging/helm/openwork-ee/templates/externalsecret.yaml index caa803c8fd..1bd56a825f 100644 --- a/packaging/helm/openwork-ee/templates/externalsecret.yaml +++ b/packaging/helm/openwork-ee/templates/externalsecret.yaml @@ -29,9 +29,17 @@ spec: name: {{ include "openwork-ee.secretName" . }} creationPolicy: {{ .Values.externalSecrets.target.creationPolicy | default "Owner" }} deletionPolicy: {{ .Values.externalSecrets.target.deletionPolicy | default "Retain" }} + {{- /* + Only the three boot-critical keys are required in the provider; every other + entry is optional so a missing optional key (e.g. DAYTONA_API_KEY when the + provisioner is stub) does not block the whole Secret — ESO skips absent + optional keys and still materializes the Secret. Requires ESO >= 0.5.3 + (remoteRef.optional), served by both v1beta1 and v1. + */}} + {{- $requiredKeys := list "databaseUrl" "betterAuthSecret" "denDbEncryptionKey" }} data: {{- $prefix := .Values.externalSecrets.pathPrefix | toString | trim | trimSuffix "/" }} - {{- range $name := keys .Values.secret.keys | sortAlpha }} + {{- range $name := keys $.Values.secret.keys | sortAlpha }} {{- $envKey := index $.Values.secret.keys $name }} - secretKey: {{ $envKey | quote }} remoteRef: @@ -39,5 +47,8 @@ spec: conversionStrategy: {{ $.Values.externalSecrets.conversionStrategy }} decodingStrategy: {{ $.Values.externalSecrets.decodingStrategy }} metadataPolicy: {{ $.Values.externalSecrets.metadataPolicy }} + {{- if not (has $name $requiredKeys) }} + optional: true + {{- end }} {{- end }} {{- end }} diff --git a/packaging/helm/openwork-ee/tests/external-secrets.sh b/packaging/helm/openwork-ee/tests/external-secrets.sh index ed740ba970..6de2ef3a70 100755 --- a/packaging/helm/openwork-ee/tests/external-secrets.sh +++ b/packaging/helm/openwork-ee/tests/external-secrets.sh @@ -91,6 +91,9 @@ assert_contains "$enabled_rendered" 'key: "eks/openwork/prod/den/DEN_INITIAL_ADM assert_count "$enabled_rendered" 'conversionStrategy: Default' 20 assert_count "$enabled_rendered" 'decodingStrategy: None' 20 assert_count "$enabled_rendered" 'metadataPolicy: None' 20 +# Only the three boot-critical keys are required in the provider; the other 17 +# are optional so a missing optional key does not block the whole Secret. +assert_count "$enabled_rendered" 'optional: true' 17 # Target Secret keeps the chart secret name so envFrom/secretKeyRef wiring holds. # 7 name: occurrences: ExternalSecret metadata.name + target.name, envFrom in assert_count "$enabled_rendered" 'name: "openwork-ee-secret"' 7 @@ -133,7 +136,7 @@ secret: YAML padded_existing_rendered="$tmp_dir/padded-existing.yaml" helm template openwork-ee "$chart_dir" -f "$padded_existing_values" > "$padded_existing_rendered" -assert_count "$padded_existing_rendered" 'name: padded-secret' 5 +assert_count "$padded_existing_rendered" 'name: "padded-secret"' 5 assert_not_contains "$padded_existing_rendered" ' padded-secret' assert_count "$enabled_rendered" 'helm.sh/hook-weight": "-10"' 1 assert_count "$enabled_rendered" 'helm.sh/hook-weight": "-6"' 3 @@ -392,6 +395,6 @@ YAML helm template openwork-ee "$chart_dir" -f "$tmp_dir/existing-values.yaml" > "$existing_rendered" assert_count "$existing_rendered" 'kind: Secret' 0 assert_count "$existing_rendered" 'kind: ExternalSecret' 0 -assert_count "$existing_rendered" 'name: manually-managed' 5 +assert_count "$existing_rendered" 'name: "manually-managed"' 5 printf 'external-secrets chart checks passed\n'