Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion charts/plane-enterprise/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Meet Plane. An Enterprise software development tool to manage issue

type: application

version: 3.11.3
version: 3.11.4
appVersion: "4.0.1"

home: https://plane.so/
Expand Down
14 changes: 3 additions & 11 deletions charts/plane-enterprise/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1736,18 +1736,11 @@ From chart 3.6.0 onward that Secret is rendered as base64 `data` rather than `st
Helm can express the deletion and this stops recurring. The one-time cleanup above is still
needed for the upgrade that crosses into 3.6.0.

### 6. Secrets that live in the database, not the environment
### 6. Settings managed in god-mode, not the environment

By default (`SKIP_ENV_VAR=1`) the API reads about twenty settings — SMTP password, Google/GitHub/GitLab/OIDC client secrets, `LLM_API_KEY`, `LDAP_BIND_PASSWORD`, SAML certificate — from the instance-configuration table, seeded from the environment only on first startup. **Rotating those through a Secret has no effect** while that is the case.
Instance settings — sign-in methods, Google/GitHub/GitLab/Gitea/OIDC/SAML/LDAP, SMTP (including its password), `LLM_API_KEY` and the other options on the god-mode admin pages — are managed in the god-mode admin UI by design and stored in the database. Environment variables do not configure them, so **rotating them through a Secret has no effect**: change them in god-mode.

Set `env.skip_env_var: '0'` to make the API re-read them from the environment on every start, which makes the external secret the source of truth:

```yaml
env:
skip_env_var: '0'
```

The trade-off: edits made to those settings in the god-mode admin UI are overwritten on the next restart.
Earlier chart versions documented `env.skip_env_var: '0'` for this. It never changed what the API reads, and it has been removed from `values.yaml`. If you set it, save those settings in god-mode first, then remove it: while it is set, worker, beat and the consumers read the environment instead of the database and can disagree with the API.

### AI providers, including Amazon Bedrock

Expand Down Expand Up @@ -1805,7 +1798,6 @@ chart: an empty credential is *present*, and a present credential denies the cha
| `external_secrets.app_keys_existingSecret` | | One Secret for the shared signing/encryption keys. |
| `external_secrets.ssl_token_existingSecret` | | DNS-01 API token for the cert-manager Issuer; must contain the key `api-token`. |
| `env.requireExplicitSecrets` | false | Fail the render instead of falling back to the chart's public example keys. Will default to `true` in the next major version. |
| `env.skip_env_var` | '1' | `'0'` makes the API re-read the database-resident secrets (SMTP, OAuth, LLM, LDAP) from the environment on every start. |
| `global.forceRedeploy` | false | Restart every workload on every `helm upgrade`, as versions before 3.1.0 did. Off means upgrades roll only what changed. |

### Provider examples
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Both fail **silently**: decryption errors are swallowed and the values come back

**The bundled `local_setup` infrastructure is out of scope.** The chart's own postgres/rabbitmq/minio/opensearch StatefulSets are intended for local and evaluation use; rotating their credentials means changing the password inside the container as well, which the chart does not orchestrate. Everything here assumes managed backends.

**Database-resident secrets do not rotate through the environment.** With the default `SKIP_ENV_VAR=1`, the SMTP password, OAuth client secrets, `LLM_API_KEY` and `LDAP_BIND_PASSWORD` live in the instance-configuration table, seeded from the environment only on first boot. Set `env.skip_env_var: '0'` to make the environment the source of truth on every restart — at the cost of god-mode admin UI edits to those settings being overwritten.
**Database-resident secrets do not rotate through the environment.** The SMTP password, OAuth client secrets, `LLM_API_KEY` and `LDAP_BIND_PASSWORD` are managed in the god-mode admin UI and stored in the database, by design. Rotate them there; changing the Secret has no effect. (`env.skip_env_var` does not change this and is no longer a chart value.)

**Silo, live and Plane AI rotate like the API from planeVersion v3.2.0** — they read
discrete parts, so nothing recomposes a DSN and a Reloader restart is all that is needed.
Expand Down
7 changes: 5 additions & 2 deletions charts/plane-enterprise/templates/NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,11 @@ Warn rather than reorder: reordering would change which value existing installs
{{- end }}

{{- /* Secrets that env rotation cannot reach. */}}
{{- if and (eq (.Values.env.skip_env_var | default "1" | toString) "1") (or .Values.external_secrets.app_keys_existingSecret $externalInfra) }}
{{- $warnings = append $warnings "env.skip_env_var is '1', so the SMTP password, OAuth client secrets, LLM_API_KEY\n and LDAP_BIND_PASSWORD are read from the instance-configuration table in the\n database, seeded from the environment only on first startup. Rotating those through\n a Secret will have no effect. Set env.skip_env_var='0' to make the environment the\n source of truth on every restart." }}
{{- if or .Values.external_secrets.app_keys_existingSecret $externalInfra }}
{{- $warnings = append $warnings "The SMTP password, OAuth client secrets, LLM_API_KEY and LDAP_BIND_PASSWORD are\n managed in the god-mode admin UI and stored in the database, not read from the\n environment. Rotating them through a Secret has no effect; change them in god-mode." }}
{{- end }}
{{- if ne (.Values.env.skip_env_var | default "1" | toString) "1" }}
{{- $warnings = append $warnings "env.skip_env_var is no longer a chart value. Instance settings are managed in\n god-mode and the API ignores '0', but worker, beat and the consumers read the\n environment while it is set, so they can disagree with the API. Save those settings\n in god-mode, then remove env.skip_env_var." }}
{{- end }}

{{- /* Static object-storage keys where a cloud identity would do. */}}
Expand Down
6 changes: 3 additions & 3 deletions charts/plane-enterprise/templates/config-secrets/app-env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ data:
PAYMENT_SERVER_BASE_URL: {{ .Values.license.licenseServer | quote }}

DEFAULT_API_RATE_LIMIT: {{ .Values.env.api_key_rate_limit | default "120/minute" | quote }}
{{- /* '0' makes the API re-read SMTP/OAuth/LLM/LDAP secrets from the environment on
every start instead of from the instance-configuration table, which is what
lets an external secret store rotate them. See values.yaml env.skip_env_var. */}}
{{- /* Instance settings are managed in god-mode by design; the API always reads them
from the database. env.skip_env_var is no longer in values.yaml: the default
keeps existing releases unchanged, and NOTES warns about an explicit '0'. */}}
SKIP_ENV_VAR: {{ .Values.env.skip_env_var | default "1" | quote }}
MINIO_ENDPOINT_SSL: {{ .Values.services.minio.env.minio_endpoint_ssl | default false | ternary "1" "0" | quote }}
USE_STORAGE_PROXY: {{ .Values.env.use_storage_proxy | default false | ternary "1" "0" | quote }}
Expand Down
8 changes: 0 additions & 8 deletions charts/plane-enterprise/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1185,14 +1185,6 @@ env:
# the next major version.
requireExplicitSecrets: false

# SKIP_ENV_VAR=1 (the default) makes the API read SMTP, OAuth-provider, LLM and
# LDAP secrets from the instance-configuration table in the database, seeded from
# the environment only on first startup — so rotating those through a Secret has
# no effect. Set '0' when an external secret store is the source of truth: the
# API then re-seeds them from the environment on every start. Trade-off: edits
# made in the god-mode admin UI for those settings get overwritten on restart.
skip_env_var: '1'

# Kubernetes internal cluster domain used to build in-cluster service URLs
default_cluster_domain: 'cluster.local'

Expand Down