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
4 changes: 2 additions & 2 deletions charts/plane-enterprise/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ description: Meet Plane. An Enterprise software development tool to manage issue

type: application

version: 2.8.1
appVersion: "2.6.4"
version: 3.0.0
appVersion: "3.0.0"

home: https://plane.so/
icon: https://plane.so/favicon/favicon-32x32.png
Expand Down
32 changes: 28 additions & 4 deletions charts/plane-enterprise/README.md

Large diffs are not rendered by default.

58 changes: 57 additions & 1 deletion charts/plane-enterprise/questions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ questions:
- variable: planeVersion
label: Plane Version (Docker Image Tag)
type: string
default: v2.6.4
default: v3.0.0
required: true
group: "Docker Registry"
subquestions:
Expand Down Expand Up @@ -347,6 +347,10 @@ questions:
label: "Jira Server Issues Parallel Pages"
type: int
default: 1
- variable: env.silo_envs.cursor_webhook_secret
label: "Cursor Webhook Secret"
type: string
default: "TTqazTcoBajYKzIAeIKFZeTX9czAoUsG"

- variable: services.silo.connectors.slack.enabled
label: "Slack Integration"
Expand All @@ -363,6 +367,10 @@ questions:
label: "Slack Client Secret"
type: string
default: ""
- variable: services.silo.connectors.slack.base_url
label: "Slack Base URL"
type: string
default: ""

- variable: services.silo.connectors.github.enabled
label: "Github App Integration"
Expand Down Expand Up @@ -534,6 +542,14 @@ questions:
label: "Web URL"
type: string
default: ""
- variable: env.webhook_allowed_ips
label: "Webhook Allowed IPs"
type: string
default: ""
- variable: env.webhook_allowed_hosts
label: "Webhook Allowed Hosts"
type: string
default: ""
- variable: services.external_api.enabled
label: "Enable External API"
type: boolean
Expand Down Expand Up @@ -827,6 +843,46 @@ questions:
type: string
default: "issue"

- variable: services.webhook_consumer.enabled
label: "Enable Webhook Consumer"
type: boolean
default: false
group: "Webhook Consumer Setup"
show_subquestion_if: true
subquestions:
- variable: services.webhook_consumer.replicas
label: "Default Replica Count"
type: int
default: 1
- variable: services.webhook_consumer.memoryLimit
label: "Memory Limit"
type: string
default: 1000Mi
- variable: services.webhook_consumer.cpuLimit
label: "CPU Limit"
type: string
default: 500m
- variable: services.webhook_consumer.memoryRequest
label: "Memory Request"
type: string
default: 500Mi
- variable: services.webhook_consumer.cpuRequest
label: "CPU Request"
type: string
default: 250m
- variable: services.webhook_consumer.assign_cluster_ip
label: "Assign Cluster IP"
type: boolean
default: false
- variable: env.webhook_consumer_envs.queue_name
label: "Webhook Queue Name"
type: string
default: "plane.webhook"
- variable: env.webhook_consumer_envs.prefetch_count
label: "Webhook Prefetch Count"
type: int
default: 10

- variable: services.iframely.enabled
label: "Enable Iframely"
type: boolean
Expand Down
3 changes: 3 additions & 0 deletions charts/plane-enterprise/templates/config-secrets/app-env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,6 @@ data:
{{- else}}
CORS_ALLOWED_ORIGINS: "http://{{ .Values.license.licenseDomain }},https://{{ .Values.license.licenseDomain }}"
{{- end }}

WEBHOOK_ALLOWED_IPS: {{ .Values.env.webhook_allowed_ips | default "" | quote }}
WEBHOOK_ALLOWED_HOSTS: {{ .Values.env.webhook_allowed_hosts | default "" | quote }}
2 changes: 2 additions & 0 deletions charts/plane-enterprise/templates/config-secrets/silo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ metadata:
stringData:
SILO_HMAC_SECRET_KEY: {{ .Values.env.silo_envs.hmac_secret_key | default "gzb7MRLr0FoN129NyWARZEs84P9LzQ" | quote }}
AES_SECRET_KEY: {{ .Values.env.silo_envs.aes_secret_key | default "dsOdt7YrvxsTIFJ37pOaEVvLxN8KGBCr" | quote }}
CURSOR_WEBHOOK_SECRET: {{ .Values.env.silo_envs.cursor_webhook_secret | default "TTqazTcoBajYKzIAeIKFZeTX9czAoUsG" | quote }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Use a unique, required Cursor webhook secret instead of a public fallback.

The chart currently emits a predictable secret when unset, while the README documents the same value. This permits forged Cursor webhook requests in default installations.

  • charts/plane-enterprise/templates/config-secrets/silo.yaml#L14-L14: remove the static fallback and require an externally supplied or persistently generated secret.
  • charts/plane-enterprise/README.md#L571-L571: document the value as required/generated rather than providing a default.
  • charts/plane-enterprise/README.md#L895-L895: replace the static example with a placeholder such as <your_random_secret>.
📍 Affects 2 files
  • charts/plane-enterprise/templates/config-secrets/silo.yaml#L14-L14 (this comment)
  • charts/plane-enterprise/README.md#L571-L571
  • charts/plane-enterprise/README.md#L895-L895
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@charts/plane-enterprise/templates/config-secrets/silo.yaml` at line 14,
Remove the predictable fallback from CURSOR_WEBHOOK_SECRET in
charts/plane-enterprise/templates/config-secrets/silo.yaml:14-14 and require an
externally supplied or persistently generated secret. Update
charts/plane-enterprise/README.md:571-571 to describe the value as
required/generated, and replace the static example at
charts/plane-enterprise/README.md:895-895 with a placeholder such as
<your_random_secret>.


{{- if .Values.services.postgres.local_setup }}
DATABASE_URL: "postgresql://{{ .Values.env.pgdb_username }}:{{ .Values.env.pgdb_password }}@{{ .Release.Name }}-pgdb.{{ .Release.Namespace }}.svc.{{ .Values.env.default_cluster_domain | default "cluster.local" }}/{{ .Values.env.pgdb_name }}"
Expand All @@ -37,6 +38,7 @@ stringData:
{{- if .Values.services.silo.connectors.slack.enabled }}
SLACK_CLIENT_SECRET: {{ .Values.services.silo.connectors.slack.client_secret | default "" | quote }}
SLACK_CLIENT_ID: {{ .Values.services.silo.connectors.slack.client_id | default "" | quote }}
SLACK_BASE_URL: {{ .Values.services.silo.connectors.slack.base_url | default "" | quote }}
{{- end }}
{{- if .Values.services.silo.connectors.github.enabled }}
GITHUB_CLIENT_SECRET: {{ .Values.services.silo.connectors.github.client_secret | default "" | quote }}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{- if .Values.services.webhook_consumer.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
namespace: {{ .Release.Namespace }}
name: {{ .Release.Name }}-webhook-consumer-vars
labels:
{{- include "plane.commonLabels" $ | nindent 4 }}
data:
WEBHOOK_QUEUE_NAME: {{ .Values.env.webhook_consumer_envs.queue_name | default "plane.webhook" | quote }}
WEBHOOK_PREFETCH_COUNT: {{ .Values.env.webhook_consumer_envs.prefetch_count | default 10 | quote }}
---
{{- end }}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ spec:
containers:
- name: {{ .Release.Name }}-automation-consumer
{{- include "plane.containerSecurityContext" . }}
imagePullPolicy: Always
imagePullPolicy: {{ .Values.services.api.pullPolicy | default "Always" }}
image: {{ .Values.services.api.image | default "makeplane/backend-commercial" }}:{{ .Values.planeVersion }}
stdin: true
tty: true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{{- if .Values.services.webhook_consumer.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: {{ .Release.Namespace }}
name: {{ .Release.Name }}-webhook-consumer-wl
{{- include "plane.labelsAndAnnotations" (dict "context" $ "values" .Values.services.webhook_consumer) }}
spec:
replicas: {{ .Values.services.webhook_consumer.replicas | default 1 }}
selector:
matchLabels:
app.name: {{ .Release.Namespace }}-{{ .Release.Name }}-webhook-consumer
template:
metadata:
namespace: {{ .Release.Namespace }}
labels:
app.name: {{ .Release.Namespace }}-{{ .Release.Name }}-webhook-consumer
{{- include "plane.commonLabels" $ | nindent 8 }}
annotations:
timestamp: {{ now | quote }}
spec:
{{- include "plane.podScheduling" .Values.services.webhook_consumer }}
{{- include "plane.podSecurityContext" . }}
containers:
- name: {{ .Release.Name }}-webhook-consumer
{{- include "plane.containerSecurityContext" . }}
imagePullPolicy: {{ .Values.services.api.pullPolicy | default "Always" }}
image: {{ .Values.services.api.image | default "makeplane/backend-commercial" }}:{{ .Values.planeVersion }}
stdin: true
tty: true
resources:
requests:
memory: {{ .Values.services.webhook_consumer.memoryRequest | default "500Mi" | quote }}
cpu: {{ .Values.services.webhook_consumer.cpuRequest | default "250m" | quote }}
limits:
memory: {{ .Values.services.webhook_consumer.memoryLimit | default "1000Mi" | quote }}
cpu: {{ .Values.services.webhook_consumer.cpuLimit | default "500m" | quote}}
readinessProbe:
exec:
command:
- sh
- -c
- pgrep -f "python" > /dev/null
initialDelaySeconds: 10
failureThreshold: 3
periodSeconds: 30
successThreshold: 1
timeoutSeconds: 5
command:
- ./bin/docker-entrypoint-webhook-consumer.sh
envFrom:
- configMapRef:
name: {{ .Release.Name }}-webhook-consumer-vars
optional: false
- configMapRef:
name: {{ .Release.Name }}-app-vars
optional: false
- secretRef:
name: {{ if not (empty .Values.external_secrets.app_env_existingSecret) }}{{ .Values.external_secrets.app_env_existingSecret }}{{ else }}{{ .Release.Name }}-app-secrets{{ end }}
optional: false
- secretRef:
name: {{ if not (empty .Values.external_secrets.doc_store_existingSecret) }}{{ .Values.external_secrets.doc_store_existingSecret }}{{ else }}{{ .Release.Name }}-doc-store-secrets{{ end }}
optional: false
- secretRef:
name: {{ if not (empty .Values.external_secrets.opensearch_existingSecret) }}{{ .Values.external_secrets.opensearch_existingSecret }}{{ else }}{{ .Release.Name }}-opensearch-secrets{{ end }}
optional: false
{{- if .Values.services.silo.enabled }}
- secretRef:
name: {{ if not (empty .Values.external_secrets.silo_env_existingSecret) }}{{ .Values.external_secrets.silo_env_existingSecret }}{{ else }}{{ .Release.Name }}-silo-secrets{{ end }}
optional: false
{{- end }}
{{- if .Values.extraEnv }}
env:
{{- toYaml .Values.extraEnv | nindent 10 }}
{{- end }}

serviceAccount: {{ .Release.Name }}-srv-account
serviceAccountName: {{ .Release.Name }}-srv-account
---
{{- end }}
28 changes: 26 additions & 2 deletions charts/plane-enterprise/values.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
planeVersion: v2.6.4
planeVersion: v3.0.0

dockerRegistry:
enabled: false
Expand Down Expand Up @@ -359,6 +359,7 @@ services:
enabled: false
client_id: ''
client_secret: ''
base_url: ''
github:
enabled: false
client_id: ''
Expand Down Expand Up @@ -414,7 +415,20 @@ services:
cpuLimit: 500m
memoryRequest: 50Mi
cpuRequest: 50m
pullPolicy: Always
assign_cluster_ip: false
nodeSelector: {}
tolerations: []
affinity: {}
labels: {}
annotations: {}

webhook_consumer:
enabled: false
replicas: 1
memoryLimit: 1000Mi
cpuLimit: 500m
memoryRequest: 500Mi
cpuRequest: 250m
assign_cluster_ip: false
nodeSelector: {}
tolerations: []
Expand Down Expand Up @@ -591,6 +605,11 @@ env:
instance_admin_email: ''
web_url: ''

# Comma-separated list of IPs/CIDRs and hostnames that webhooks are allowed to target.
# Leave empty to allow all (no restriction).
webhook_allowed_ips: ''
webhook_allowed_hosts: ''

live_sentry_dsn: ""
live_sentry_environment: ""
live_sentry_traces_sample_rate: ""
Expand All @@ -610,6 +629,7 @@ env:
cors_allowed_origins: ''
jira_server_issues_page_size: 50
jira_server_issues_parallel_pages: 1
cursor_webhook_secret: 'TTqazTcoBajYKzIAeIKFZeTX9czAoUsG'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not ship a shared default webhook secret.

cursor_webhook_secret is committed as a fixed non-empty value and, per the PR context, is rendered into the Silo Secret. Every installation using chart defaults therefore shares a predictable credential, allowing forged Cursor webhook requests. Require an installation-specific value from an external secret or fail rendering when it is unset.

Proposed direction
-    cursor_webhook_secret: 'TTqazTcoBajYKzIAeIKFZeTX9czAoUsG'
+    cursor_webhook_secret: ''

Then enforce it with Helm’s required helper in the Secret template, or source it exclusively from an ExternalSecret.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cursor_webhook_secret: 'TTqazTcoBajYKzIAeIKFZeTX9czAoUsG'
cursor_webhook_secret: ''
🧰 Tools
🪛 Betterleaks (1.6.1)

[high] 632-632: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@charts/plane-enterprise/values.yaml` at line 632, Remove the fixed non-empty
default for cursor_webhook_secret and require an installation-specific value.
Update the chart’s Silo Secret template to enforce the value with Helm’s
required helper, or source it exclusively from an ExternalSecret, so rendering
fails when no secret is provided.

Source: Linters/SAST tools


email_service_envs:
smtp_domain: ''
Expand Down Expand Up @@ -637,6 +657,10 @@ env:
exchange_name: "plane.event_stream"
event_types: "issue"

webhook_consumer_envs:
queue_name: "plane.webhook"
prefetch_count: 10

runner_envs:
execution_timeout_ms: "10000"
init_timeout_ms: "5000"
Expand Down