Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
x-db-env: &db-env
PGHOST: ${PGHOST:-plane-db}
PGDATABASE: ${PGDATABASE:-plane}
POSTGRES_USER: ${POSTGRES_USER:-plane}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-plane}
POSTGRES_DB: ${POSTGRES_DB:-plane}
POSTGRES_PORT: ${POSTGRES_PORT:-5432}
PGDATA: ${PGDATA:-/var/lib/postgresql/data}

x-redis-env: &redis-env
REDIS_HOST: ${REDIS_HOST:-plane-redis}
REDIS_PORT: ${REDIS_PORT:-6379}
REDIS_URL: ${REDIS_URL:-redis://plane-redis:6379/}

x-minio-env: &minio-env
MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID:-access-key}
MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY:-secret-key}

x-aws-s3-env: &aws-s3-env
AWS_REGION: ${AWS_REGION:-}
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-access-key}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-secret-key}
AWS_S3_ENDPOINT_URL: ${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
AWS_S3_BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}


# SMTP (GMAIL)
EMAIL_BACKEND: django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST: smtp.gmail.com
EMAIL_PORT: 587
EMAIL_USE_TLS: "1"
EMAIL_HOST_USER: ${EMAIL_HOST_USER}
EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD}
DEFAULT_FROM_EMAIL: ${DEFAULT_FROM_EMAIL}
Comment on lines +27 to +34
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

SMTP configuration lacks environment variable support.

The SMTP configuration is hardcoded in the x-aws-s3-env anchor without environment variable placeholders:

EMAIL_BACKEND: django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST: smtp.gmail.com
EMAIL_PORT: 587
EMAIL_USE_TLS: "1"
EMAIL_HOST_USER: ${EMAIL_HOST_USER}
EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD}
DEFAULT_FROM_EMAIL: ${DEFAULT_FROM_EMAIL}

Issues:

  1. Architectural concern: SMTP configuration is placed in the aws-s3-env anchor, which is meant for S3/MinIO settings. This is confusing and violates separation of concerns.
  2. Hardcoded values: EMAIL_BACKEND, EMAIL_HOST, EMAIL_PORT, and EMAIL_USE_TLS are hardcoded to Gmail-specific values, making it difficult to use other SMTP providers without editing the file.

Recommended refactor:

♻️ Create a separate SMTP environment anchor
+x-smtp-env: &smtp-env
+  EMAIL_BACKEND: ${EMAIL_BACKEND:-django.core.mail.backends.smtp.EmailBackend}
+  EMAIL_HOST: ${EMAIL_HOST:-smtp.gmail.com}
+  EMAIL_PORT: ${EMAIL_PORT:-587}
+  EMAIL_USE_TLS: ${EMAIL_USE_TLS:-1}
+  EMAIL_HOST_USER: ${EMAIL_HOST_USER}
+  EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD}
+  DEFAULT_FROM_EMAIL: ${DEFAULT_FROM_EMAIL}
+
 x-aws-s3-env: &aws-s3-env
   AWS_REGION: ${AWS_REGION:-}
   AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-access-key}
   AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-secret-key}
   AWS_S3_ENDPOINT_URL: ${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
   AWS_S3_BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
-
-  # SMTP (GMAIL)
-  EMAIL_BACKEND: django.core.mail.backends.smtp.EmailBackend
-  EMAIL_HOST: smtp.gmail.com
-  EMAIL_PORT: 587
-  EMAIL_USE_TLS: "1"
-  EMAIL_HOST_USER: ${EMAIL_HOST_USER}
-  EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD}
-  DEFAULT_FROM_EMAIL: ${DEFAULT_FROM_EMAIL}

Then merge *smtp-env into services that require email functionality:

     environment:
-      <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env]
+      <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *smtp-env, *proxy-env]
🤖 Prompt for AI Agents
In @deployments/cli/community/plane-app/archive/1767865532.docker-compose.yaml
around lines 27 - 34, The SMTP settings are placed in the x-aws-s3-env anchor
and contain hardcoded Gmail values; extract these into a new reusable anchor
named x-smtp-env with environment-variable placeholders for EMAIL_BACKEND,
EMAIL_HOST, EMAIL_PORT, EMAIL_USE_TLS, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, and
DEFAULT_FROM_EMAIL, remove the SMTP keys from x-aws-s3-env, and update any
services that need email to include the new anchor by merging *smtp-env into
their environment sections so providers can be swapped via env vars without
editing the compose file.


x-proxy-env: &proxy-env
APP_DOMAIN: ${APP_DOMAIN:-localhost}
FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880}
CERT_EMAIL: ${CERT_EMAIL}
CERT_ACME_CA: ${CERT_ACME_CA}
CERT_ACME_DNS: ${CERT_ACME_DNS}
LISTEN_HTTP_PORT: ${LISTEN_HTTP_PORT:-80}
LISTEN_HTTPS_PORT: ${LISTEN_HTTPS_PORT:-443}
BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
SITE_ADDRESS: ${SITE_ADDRESS:-:80}

x-mq-env: &mq-env # RabbitMQ Settings
RABBITMQ_HOST: ${RABBITMQ_HOST:-plane-mq}
RABBITMQ_PORT: ${RABBITMQ_PORT:-5672}
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-plane}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-plane}
RABBITMQ_DEFAULT_VHOST: ${RABBITMQ_VHOST:-plane}
RABBITMQ_VHOST: ${RABBITMQ_VHOST:-plane}

x-live-env: &live-env
API_BASE_URL: ${API_BASE_URL:-http://api:8000}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-2FiJk1U2aiVPEQtzLehYGlTSnTnrs7LW}

x-app-env: &app-env
WEB_URL: ${WEB_URL:-http://localhost}
DEBUG: ${DEBUG:-0}
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS}
GUNICORN_WORKERS: 1
USE_MINIO: ${USE_MINIO:-1}
DATABASE_URL: ${DATABASE_URL:-postgresql://plane:plane@plane-db/plane}
SECRET_KEY: ${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane}
API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute}
MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-2FiJk1U2aiVPEQtzLehYGlTSnTnrs7LW}

services:
web:
image: artifacts.plane.so/makeplane/plane-frontend:${APP_RELEASE:-v1.2.1}
deploy:
replicas: ${WEB_REPLICAS:-1}
restart_policy:
condition: any
depends_on:
- api
- worker

space:
image: artifacts.plane.so/makeplane/plane-space:${APP_RELEASE:-v1.2.1}
deploy:
replicas: ${SPACE_REPLICAS:-1}
restart_policy:
condition: any
depends_on:
- api
- worker
- web

admin:
image: artifacts.plane.so/makeplane/plane-admin:${APP_RELEASE:-v1.2.1}
deploy:
replicas: ${ADMIN_REPLICAS:-1}
restart_policy:
condition: any
depends_on:
- api
- web

live:
image: artifacts.plane.so/makeplane/plane-live:${APP_RELEASE:-v1.2.1}
environment:
<<: [*live-env, *redis-env]
deploy:
replicas: ${LIVE_REPLICAS:-1}
restart_policy:
condition: any
depends_on:
- api
- web

api:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.1}
command: ./bin/docker-entrypoint-api.sh
deploy:
replicas: ${API_REPLICAS:-1}
restart_policy:
condition: any
volumes:
- logs_api:/code/plane/logs
environment:
<<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env]
depends_on:
- plane-db
- plane-redis
- plane-mq

worker:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.1}
command: ./bin/docker-entrypoint-worker.sh
deploy:
replicas: ${WORKER_REPLICAS:-1}
restart_policy:
condition: any
volumes:
- logs_worker:/code/plane/logs
environment:
<<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env]
depends_on:
- api
- plane-db
- plane-redis
- plane-mq

beat-worker:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.1}
command: ./bin/docker-entrypoint-beat.sh
deploy:
replicas: ${BEAT_WORKER_REPLICAS:-1}
restart_policy:
condition: any
volumes:
- logs_beat-worker:/code/plane/logs
environment:
<<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env]
depends_on:
- api
- plane-db
- plane-redis
- plane-mq

migrator:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v1.2.1}
command: ./bin/docker-entrypoint-migrator.sh
deploy:
replicas: 1
restart_policy:
condition: on-failure
volumes:
- logs_migrator:/code/plane/logs
environment:
<<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env]
depends_on:
- plane-db
- plane-redis

# Comment this if you already have a database running
plane-db:
image: postgres:15.7-alpine
command: postgres -c 'max_connections=1000'
deploy:
replicas: 1
restart_policy:
condition: any
environment:
<<: *db-env
volumes:
- pgdata:/var/lib/postgresql/data

plane-redis:
image: valkey/valkey:7.2.11-alpine
deploy:
replicas: 1
restart_policy:
condition: any
volumes:
- redisdata:/data

plane-mq:
image: rabbitmq:3.13.6-management-alpine
deploy:
replicas: 1
restart_policy:
condition: any
environment:
<<: *mq-env
volumes:
- rabbitmq_data:/var/lib/rabbitmq

# Comment this if you using any external s3 compatible storage
plane-minio:
image: minio/minio:latest
command: server /export --console-address ":9090"
deploy:
replicas: 1
restart_policy:
condition: any
environment:
<<: *minio-env
volumes:
- uploads:/export

# Comment this if you already have a reverse proxy running
proxy:
image: artifacts.plane.so/makeplane/plane-proxy:${APP_RELEASE:-v1.2.1}
deploy:
replicas: 1
restart_policy:
condition: any
environment:
<<: *proxy-env
ports:
- target: 80
published: ${LISTEN_HTTP_PORT:-80}
protocol: tcp
mode: host
- target: 443
published: ${LISTEN_HTTPS_PORT:-443}
protocol: tcp
mode: host
volumes:
- proxy_config:/config
- proxy_data:/data
depends_on:
- web
- api
- space
- admin
- live

volumes:
pgdata:
redisdata:
uploads:
logs_api:
logs_worker:
logs_beat-worker:
logs_migrator:
rabbitmq_data:
proxy_config:
proxy_data:
101 changes: 101 additions & 0 deletions deployments/cli/community/plane-app/archive/1767865532.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
APP_DOMAIN=localhost
APP_RELEASE=v1.2.1

WEB_REPLICAS=1
SPACE_REPLICAS=1
ADMIN_REPLICAS=1
API_REPLICAS=1
WORKER_REPLICAS=1
BEAT_WORKER_REPLICAS=1
LIVE_REPLICAS=1

LISTEN_HTTP_PORT=80
LISTEN_HTTPS_PORT=443

WEB_URL=http://${APP_DOMAIN}
DEBUG=0
CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN}
API_BASE_URL=http://api:8000

#DB SETTINGS
PGHOST=host.docker.internal
PGDATABASE=plane
POSTGRES_USER=postgres
POSTGRES_PASSWORD=root
POSTGRES_DB=plane
POSTGRES_PORT=5432
PGDATA=/var/lib/postgresql/data
DATABASE_URL=postgres://postgres:[email protected]:5432/plane

# REDIS SETTINGS
REDIS_HOST=host.docker.internal
REDIS_PORT=6379
REDIS_URL=redis://host.docker.internal:6379/0

# RabbitMQ Settings
RABBITMQ_HOST=host.docker.internal
RABBITMQ_PORT=5672
RABBITMQ_USER=plane
RABBITMQ_PASSWORD=plane
RABBITMQ_VHOST=plane
AMQP_URL=

# =========================
# SMTP SETTINGS (GMAIL)
# =========================
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend

EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=1

[email protected]
EMAIL_HOST_PASSWORD=gdkbknshfszmtxlh

DEFAULT_FROM_EMAIL="Plane <[email protected]>"

Comment on lines +46 to +56
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

CRITICAL: Exposed SMTP credentials in version control.

Real Gmail credentials are hardcoded in this file:

  • [email protected]
  • EMAIL_HOST_PASSWORD=gdkbknshfszmtxlh (appears to be a valid Gmail app password)

This is a severe security vulnerability. These credentials are now exposed in version control and in the public GitHub repository.

Immediate actions required:

  1. Revoke the Gmail app password immediately
  2. Remove these credentials from the file and use environment variable placeholders instead
  3. Consider removing this file from git history using tools like git filter-branch or BFG Repo-Cleaner
  4. Review if the email account was compromised

Recommended fix:

-[email protected]
-EMAIL_HOST_PASSWORD=gdkbknshfszmtxlh
+EMAIL_HOST_USER=${EMAIL_HOST_USER}
+EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @deployments/cli/community/plane-app/archive/1767865532.env around lines 46 -
56, Remove the hardcoded Gmail credentials by replacing the literal values for
EMAIL_HOST_USER and EMAIL_HOST_PASSWORD with environment variable placeholders
(e.g., EMAIL_HOST_USER=${EMAIL_HOST_USER} and
EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD}) and change DEFAULT_FROM_EMAIL to
reference the same env var or a separate DEFAULT_FROM_EMAIL placeholder; add the
actual .env file to .gitignore, add a sanitized .env.example with placeholder
values and instructions, and after making these changes immediately
rotate/revoke the exposed Gmail app password and document the credential
rotation; lastly, purge the secret from git history (e.g., BFG or git
filter-branch) and notify the security/owner to validate account compromise.



# If SSL Cert to be generated, set CERT_EMAIl="email <EMAIL_ADDRESS>"
CERT_ACME_CA=https://acme-v02.api.letsencrypt.org/directory
TRUSTED_PROXIES=0.0.0.0/0
SITE_ADDRESS=:80
CERT_EMAIL=



# For DNS Challenge based certificate generation, set the CERT_ACME_DNS, CERT_EMAIL
# CERT_ACME_DNS="acme_dns <CERT_DNS_PROVIDER> <CERT_DNS_PROVIDER_API_KEY>"
CERT_ACME_DNS=


# Secret Key
SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Hardcoded SECRET_KEY must be rotated.

The SECRET_KEY is hardcoded in this file. If this value has been used in any deployed environment, it should be rotated immediately as it's now exposed in version control. Django's SECRET_KEY is used for:

  • Session signing
  • CSRF token generation
  • Cryptographic signing

Recommended fix:

-SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
+SECRET_KEY=${SECRET_KEY}

And provide the actual secret via environment variables at runtime.

📝 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
SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
SECRET_KEY=${SECRET_KEY}
🧰 Tools
🪛 Gitleaks (8.30.0)

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

(generic-api-key)

🤖 Prompt for AI Agents
In @deployments/cli/community/plane-app/archive/1767865532.env at line 73,
Remove the hardcoded SECRET_KEY entry and stop committing secrets to repo;
rotate the exposed SECRET_KEY immediately if it was used in any deployed
environment, then update your Django configuration (e.g., the module that
currently assigns SECRET_KEY) to read the secret from the environment at runtime
(os.environ or a secrets manager) and ensure the env var name remains SECRET_KEY
(or another agreed name) so deployments inject it securely; also add the env
file to .gitignore and update docs/CI to use secure secret provisioning.


# DATA STORE SETTINGS
USE_MINIO=1
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
AWS_S3_ENDPOINT_URL=http://host.docker.internal:9000
AWS_S3_BUCKET_NAME=uploads
FILE_SIZE_LIMIT=5242880
MINIO_ENDPOINT_SSL=0

# Gunicorn Workers
GUNICORN_WORKERS=1

# UNCOMMENT `DOCKER_PLATFORM` IF YOU ARE ON `ARM64` AND DOCKER IMAGE IS NOT AVAILABLE FOR RESPECTIVE `APP_RELEASE`
# DOCKER_PLATFORM=linux/amd64

# Force HTTPS for handling SSL Termination
MINIO_ENDPOINT_SSL=0

# API key rate limit
API_KEY_RATE_LIMIT=60/minute

# Live server environment variables
# WARNING: You must set a secure value for LIVE_SERVER_SECRET_KEY in production environments.
LIVE_SERVER_SECRET_KEY=
DOCKERHUB_USER=artifacts.plane.so/makeplane
PULL_POLICY=if_not_present
CUSTOM_BUILD=false
Loading