Repository: ioannisioannides/scopewatch
Pull request #67: Fix issue 66
Author: login: ioannisioannides
Created: 2025-04-09T22:57:08Z | Merged: 2025-04-09T22:58:48Z

Improve security of subprocess call in create_superuser function

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
	- Introduced environment-specific configuration for both development and production.
	- Added automation scripts for deployment and local setup, along with an administrative command for user management.

- **Improvements**
	- Enhanced CI/CD workflows with dynamic Python versioning and streamlined dependency checks.
	- Upgraded Docker setups with improved dependency installation, directory initialization, and flexible environment handling.
	- Refined configuration logic to smartly distinguish production, development, and test environments for increased security and reliability.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/.env.development b/.env.development
index e69de29..5a93a9c 100644
--- a/.env.development
+++ b/.env.development
@@ -0,0 +1,7 @@
+# Development environment configuration
+ENV=development
+DEBUG=True
+DJANGO_SECRET_KEY=dev-only-insecure-key-do-not-use-in-production
+ALLOWED_HOSTS=localhost,127.0.0.1
+DB_ENGINE=django.db.backends.sqlite3
+# Add any other development-specific settings here
\ No newline at end of file
diff --git a/.env.production b/.env.production
index e69de29..7f03371 100644
--- a/.env.production
+++ b/.env.production
@@ -0,0 +1,14 @@
+# Production environment configuration
+# This is a template file - do not store actual secrets in this file
+# Actual secrets should be provided via GitHub secrets
+ENV=production
+DEBUG=False
+DJANGO_SECRET_KEY=replace_with_actual_production_key
+ALLOWED_HOSTS=example.com,www.example.com,localhost,127.0.0.1
+DB_ENGINE=django.db.backends.sqlite3
+# Uncommment these lines if you switch to PostgreSQL
+# DB_NAME=scopewatch
+# DB_USER=dbuser
+# DB_PASSWORD=dbpassword
+# DB_HOST=localhost
+# DB_PORT=5432
\ No newline at end of file
diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml
index bf58d1d..731a9e4 100644
--- a/.github/workflows/ci-cd.yml
+++ b/.github/workflows/ci-cd.yml
@@ -16,7 +16,7 @@ jobs:
     - name: Set up Python
       uses: actions/setup-python@v4
       with:
-        python-version: '3.11'
+        python-version: ${{ vars.PYTHON_VERSION }}
         
     - name: Install dependencies
       run: |
@@ -35,6 +35,10 @@ jobs:
     - name: Test with pytest
       run: |
         pytest
+      env:
+        DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}
+        DEBUG: ${{ secrets.DEV_DEBUG }}
+        ALLOWED_HOSTS: 'localhost,127.0.0.1'
         
   deploy:
     needs: test
@@ -45,7 +49,11 @@ jobs:
     - uses: actions/checkout@v3
     
     # Add deployment steps here
-    # For now, this is a placeholder for your future deployment process
     - name: Deploy to production
       run: |
-        echo "Deployment would happen here"
\ No newline at end of file
+        echo "Deployment would happen here"
+      env:
+        DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}
+        DEBUG: ${{ secrets.PROD_DEBUG }}
+        ALLOWED_HOSTS: 'your-production-domain.com'
+        # Add other production environment variables as needed
\ No newline at end of file
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
index 4ea132a..2572c70 100644
--- a/.github/workflows/dependency-review.yml
+++ b/.github/workflows/dependency-review.yml
@@ -39,12 +39,6 @@ jobs:
             pip-compile requirements.in
           fi
           
-      - name: 'Python dependency submission'
-        uses: actions/dependency-submission-action@v1
-        with:
-          tool-name: 'pip-requirements'
-          manifest-file: 'requirements.txt'
-          
       - name: 'Dependency Review'
         uses: actions/dependency-review-action@v4
         with:
diff --git a/Dockerfile b/Dockerfile
index 698413a..7f8b203 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,13 +2,21 @@ FROM python:3.11-slim
 
 WORKDIR /app
 
+# Set environment variables
+ENV PYTHONDONTWRITEBYTECODE=1
+ENV PYTHONUNBUFFERED=1
+ENV DEBUG=False
+
 # Install dependencies
 COPY requirements.txt ./
-RUN pip install --no-cache-dir -r requirements.txt
+RUN pip install --no-cache-dir -r requirements.txt gunicorn
 
 # Copy project
 COPY . .
 
+# Create directories if they don't exist
+RUN mkdir -p /app/staticfiles /app/media /app/logs
+
 # Collect static files
 RUN python manage.py collectstatic --noinput
 
diff --git a/Dockerfile.dev b/Dockerfile.dev
index 6f24059..60c59bd 100644
--- a/Dockerfile.dev
+++ b/Dockerfile.dev
@@ -2,6 +2,10 @@ FROM python:3.11-slim
 
 WORKDIR /app
 
+# Set environment variables
+ENV PYTHONDONTWRITEBYTECODE=1
+ENV PYTHONUNBUFFERED=1
+
 # Install dependencies
 COPY requirements.txt requirements-dev.txt ./
 RUN pip install --no-cache-dir -r requirements.txt -r requirements-dev.txt
@@ -9,5 +13,8 @@ RUN pip install --no-cache-dir -r requirements.txt -r requirements-dev.txt
 # Copy project
 COPY . .
 
+# Create database directory if it doesn't exist
+RUN mkdir -p /app/data
+
 # Run migrations on startup
 CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
\ No newline at end of file
diff --git a/apps/management/commands/create_or_update_superuser.py b/apps/management/commands/create_or_update_superuser.py
new file mode 100644
index 0000000..8672459
--- /dev/null
+++ b/apps/management/commands/create_or_update_superuser.py
@@ -0,0 +1,49 @@
+"""
+Management command to create or update a superuser from environment variables.
+
+This command creates a superuser with credentials from environment variables,
+or updates an existing one if it already exists.
+"""
+
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth import get_user_model
+from django.db import IntegrityError
+
+from scopewatch.config import config
+
+User = get_user_model()
+
+class Command(BaseCommand):
+    """
+    Django management command to create or update a superuser with environment variables.
+    
+    This is particularly useful for automated environments like CI/CD pipelines
+    or Docker deployments where you want to ensure an admin user exists.
+    """
+    
+    help = 'Create or update a superuser using environment variables'
+    
+    def handle(self, *args, **options):
+        username = config('ADMIN_USERNAME', default=None)
+        password = config('ADMIN_PASSWORD', default=None)
+        email = config('ADMIN_EMAIL', default=None)
+        
+        if not all([username, password, email]):
+            self.stdout.write(self.style.WARNING(
+                'Admin user environment variables not set. '
+                'Set ADMIN_USERNAME, ADMIN_PASSWORD, ADMIN_EMAIL to create a superuser.'
+            ))
+            return
+            
+        try:
+            user = User.objects.get(username=username)
+            user.email = email
+            user.set_password(password)
+            user.save()
+            self.stdout.write(self.style.SUCCESS(f'Updated existing superuser: {username}'))
+        except User.DoesNotExist:
+            try:
+                User.objects.create_superuser(username=username, email=email, password=password)
+                self.stdout.write(self.style.SUCCESS(f'Created new superuser: {username}'))
+            except IntegrityError:
+                raise CommandError(f'Could not create superuser: {username}')
\ No newline at end of file
diff --git a/deploy.sh b/deploy.sh
new file mode 100755
index 0000000..fde0a83
--- /dev/null
+++ b/deploy.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+# Deployment script for Scopewatch
+# This script runs database migrations and collects static files
+
+set -e  # Exit immediately if a command exits with a non-zero status
+
+# Ensure we're in the project directory (where manage.py is located)
+cd "$(dirname "$0")"
+
+# Activate virtual environment if it exists
+if [ -d ".venv" ]; then
+  echo "Activating virtual environment..."
+  if [ -f ".venv/bin/activate" ]; then
+    source .venv/bin/activate
+  elif [ -f ".venv/Scripts/activate" ]; then
+    source .venv/Scripts/activate
+  fi
+fi
+
+# Apply database migrations
+echo "Applying database migrations..."
+python manage.py migrate
+
+# Collect static files
+echo "Collecting static files..."
+python manage.py collectstatic --noinput
+
+# Create or update superuser from environment variables
+echo "Checking for superuser credentials in environment variables..."
+python manage.py create_or_update_superuser
+
+# Start gunicorn
+echo "Starting Gunicorn server..."
+if command -v gunicorn &> /dev/null; then
+  exec gunicorn scopewatch.wsgi:application --bind 0.0.0.0:8000
+else
+  echo "Error: gunicorn not found. Please install it with: pip install gunicorn"
+  exit 1
+fi
\ No newline at end of file
diff --git a/dev.sh b/dev.sh
new file mode 100755
index 0000000..b22a5e5
--- /dev/null
+++ b/dev.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Development launcher script for Scopewatch
+# This script sets up the development environment and starts the server
+
+# Ensure we're in the project directory
+cd "$(dirname "$0")"
+
+# Create .env file from .env.development if it doesn't exist
+if [ ! -f ".env" ] && [ -f ".env.development" ]; then
+  echo "Creating .env file from .env.development..."
+  cp .env.development .env
+fi
+
+# Activate virtual environment if it exists
+if [ -d ".venv" ]; then
+  echo "Activating virtual environment..."
+  if [ -f ".venv/bin/activate" ]; then
+    source .venv/bin/activate
+  elif [ -f ".venv/Scripts/activate" ]; then
+    source .venv/Scripts/activate
+  fi
+fi
+
+# Run migrations if needed
+python manage.py migrate
+
+# Start development server
+python manage.py runserver
\ No newline at end of file
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 6dcc83b..4238ee2 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -8,10 +8,10 @@ services:
     ports:
       - "8000:8000"
     environment:
-      - DEBUG=False
-      - ALLOWED_HOSTS=localhost,127.0.0.1
-      # In production, secrets would be provided by GitHub Actions/environment
-      # DO NOT add your DJANGO_SECRET_KEY here
+      - DEBUG=${DEBUG:-False}
+      - DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY}
+      - ALLOWED_HOSTS=${ALLOWED_HOSTS:-localhost,127.0.0.1}
+      # All production secrets will be provided by GitHub Actions
     command: gunicorn scopewatch.wsgi:application --bind 0.0.0.0:8000
     volumes:
       - static_volume:/app/staticfiles
diff --git a/docker-compose.yml b/docker-compose.yml
index 255ed09..5e8b16c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -11,6 +11,8 @@ services:
       - "8000:8000"
     environment:
       - DEBUG=True
-      - DJANGO_SECRET_KEY=dev-only-insecure-key-do-not-use-in-production
+      # Use .env file for local development, secrets for CI/CD
+      - DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY:-dev-only-insecure-key-do-not-use-in-production}
       - ALLOWED_HOSTS=localhost,127.0.0.1
+      - DATABASE_URL=${DATABASE_URL:-sqlite:///db.sqlite3}
     command: python manage.py runserver 0.0.0.0:8000
\ No newline at end of file
diff --git a/scopewatch/config.py b/scopewatch/config.py
index 5d5b316..979c9a2 100644
--- a/scopewatch/config.py
+++ b/scopewatch/config.py
@@ -25,7 +25,13 @@ def get_env_file_path() -> Optional[Path]:
     """
     base_dir = Path(__file__).resolve().parent.parent
     
-    # First, check if there's a .env file in the project root
+    # First, check for environment-specific .env files
+    env = os.environ.get('ENV', 'development')
+    env_specific_path = base_dir / f".env.{env}"
+    if env_specific_path.exists():
+        return env_specific_path
+    
+    # Then, check if there's a .env file in the project root
     env_path = base_dir / ".env"
     if env_path.exists():
         return env_path
@@ -93,6 +99,28 @@ def is_debug_mode() -> bool:
     return config("DEBUG", default=False, cast=bool)
 
 
+def is_production() -> bool:
+    """
+    Check if the application is running in production mode.
+    
+    Returns:
+        bool: True if in production environment, False otherwise
+    """
+    env = os.environ.get("ENV", "").lower()
+    return env == "production" or (not is_debug_mode() and not is_test_environment())
+
+
+def is_development() -> bool:
+    """
+    Check if the application is running in development mode.
+    
+    Returns:
+        bool: True if in development environment, False otherwise
+    """
+    env = os.environ.get("ENV", "").lower()
+    return env == "development" or (is_debug_mode() and not is_test_environment())
+
+
 def is_test_environment() -> bool:
     """
     Check if the application is running in a test environment.
@@ -100,4 +128,4 @@ def is_test_environment() -> bool:
     Returns:
         bool: True if in a test environment, False otherwise
     """
-    return "test" in sys.argv or "pytest" in sys.modules
\ No newline at end of file
+    return "test" in sys.argv or "pytest" in sys.modules or os.environ.get("ENV", "").lower() == "test"
\ No newline at end of file
diff --git a/scopewatch/settings.py b/scopewatch/settings.py
index 24cafc7..66d5518 100644
--- a/scopewatch/settings.py
+++ b/scopewatch/settings.py
@@ -8,19 +8,25 @@
 from pathlib import Path
 
 # Import our custom config module instead of using decouple directly
-from scopewatch.config import config, is_debug_mode, is_test_environment
+from scopewatch.config import (
+    config, 
+    is_debug_mode, 
+    is_test_environment, 
+    is_production,
+    is_development
+)
 
 # Build paths inside the project
 BASE_DIR = Path(__file__).resolve().parent.parent
 
 # SECURITY WARNING: keep the secret key used in production secret!
 # In production, this will raise an error if the environment variable is not set
-# In development/test, it will use a placeholder (but consistent) value
-if is_debug_mode() or is_test_environment():
-    SECRET_KEY = config("DJANGO_SECRET_KEY", default="dev-only-insecure-key-do-not-use-in-production")
-else:
-    # In production, SECRET_KEY is required
+if is_production():
+    # In production, SECRET_KEY is absolutely required
     SECRET_KEY = config("DJANGO_SECRET_KEY", required=True)
+else:
+    # In development/test, allow a fallback for convenience
+    SECRET_KEY = config("DJANGO_SECRET_KEY", default="dev-only-insecure-key-do-not-use-in-production")
 
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = is_debug_mode()
@@ -38,11 +44,11 @@
 SECURE_HSTS_PRELOAD = True
 
 # By default, enable SSL redirect in production
-SECURE_SSL_REDIRECT = not (is_debug_mode() or is_test_environment())
+SECURE_SSL_REDIRECT = is_production()
 
 # Security settings based on environment
-if is_test_environment() or DEBUG:
-    # Disable all security redirects during testing
+if is_development() or is_test_environment():
+    # Disable all security redirects during testing/development
     SESSION_COOKIE_SECURE = False
     CSRF_COOKIE_SECURE = False
 else:
@@ -68,7 +74,7 @@
     "apps.organizations.apps.OrganizationsConfig",
     "apps.consultants.apps.ConsultantsConfig",
     "apps.public.apps.PublicConfig",
-    "management",  # Only keeping the root level management app for commands
+    "apps.management.apps.ManagementConfig",  # Updated to use proper AppConfig
     # Third-party apps
     "django_extensions",
     "rest_framework",
diff --git a/setup_dev_environment.py b/setup_dev_environment.py
index 24c0a92..d59048b 100755
--- a/setup_dev_environment.py
+++ b/setup_dev_environment.py
@@ -7,7 +7,6 @@
 required packages.
 """
 
-import os
 import sys
 import shutil
 import subprocess
@@ -195,11 +194,36 @@ def create_superuser():
     else:
         python_path = Path(".venv") / "bin" / "python"
     
+    # Validate that python_path exists and is within our project directory
+    python_path = python_path.resolve()
+    venv_dir = Path(".venv").resolve()
+    
+    if not python_path.exists():
+        print_error(f"Python executable not found at {python_path}")
+        return False
+        
+    if not str(python_path).startswith(str(venv_dir)):
+        print_error("Python path is outside the virtual environment directory")
+        return False
+        
     try:
-        subprocess.run([str(python_path), "manage.py", "createsuperuser"], check=False)
+        # Use a more secure approach with shell=False (the default)
+        # and a list of arguments instead of a string
+        result = subprocess.run(
+            [str(python_path), "manage.py", "createsuperuser"],
+            check=True,  # Raise exception if command fails
+            text=True,   # Return strings rather than bytes
+            capture_output=False  # Don't capture output, let it display to the user
+        )
+        
+        if result.returncode == 0:
+            print_success("Superuser created successfully.")
         return True
-    except subprocess.CalledProcessError:
-        print_error("Failed to create superuser.")
+    except subprocess.CalledProcessError as e:
+        print_error(f"Failed to create superuser. Error: {e}")
+        return False
+    except (FileNotFoundError, PermissionError) as e:
+        print_error(f"File system error occurred: {e}")
         return False
 
 


Reviews:
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T22:57:31Z
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T22:59:17Z
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T22:59:17Z

Review comments:
diff_hunk: @@ -195,11 +194,36 @@
     else:
         python_path = Path(".venv") / "bin" / "python"
     
+    # Validate that python_path exists and is within our project directory
+    python_path = python_path.resolve()
+    venv_dir = Path(".venv").resolve()
+    
+    if not python_path.exists():
+        print_error(f"Python executable not found at {python_path}")
+        return False
+        
+    if not str(python_path).startswith(str(venv_dir)):
+        print_error("Python path is outside the virtual environment directory")
+        return False
+        
     try:
-        subprocess.run([str(python_path), "manage.py", "createsuperuser"], check=False)
+        # Use a more secure approach with shell=False (the default)
+        # and a list of arguments instead of a string
+        result = subprocess.run(
+            [str(python_path), "manage.py", "createsuperuser"],
path: setup_dev_environment.py
user: login: github-advanced-security[bot]
body: subprocess call - check for execution of untrusted input.

[Show more details](https://github.com/ioannisioannides/scopewatch/security/code-scanning/426)
created_at: 2025-04-09T22:57:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -195,11 +194,36 @@
     else:
         python_path = Path(".venv") / "bin" / "python"
     
+    # Validate that python_path exists and is within our project directory
+    python_path = python_path.resolve()
+    venv_dir = Path(".venv").resolve()
+    
+    if not python_path.exists():
+        print_error(f"Python executable not found at {python_path}")
+        return False
+        
+    if not str(python_path).startswith(str(venv_dir)):
+        print_error("Python path is outside the virtual environment directory")
+        return False
+        
     try:
-        subprocess.run([str(python_path), "manage.py", "createsuperuser"], check=False)
+        # Use a more secure approach with shell=False (the default)
+        # and a list of arguments instead of a string
+        result = subprocess.run(
path: setup_dev_environment.py
user: login: github-advanced-security[bot]
body: subprocess call - check for execution of untrusted input.

[Show more details](https://github.com/ioannisioannides/scopewatch/security/code-scanning/427)
created_at: 2025-04-09T22:59:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,39 @@
+#!/bin/bash
+# Deployment script for Scopewatch
+# This script runs database migrations and collects static files
+
+set -e  # Exit immediately if a command exits with a non-zero status
+
+# Ensure we're in the project directory (where manage.py is located)
+cd "$(dirname "$0")"
+
+# Activate virtual environment if it exists
+if [ -d ".venv" ]; then
+  echo "Activating virtual environment..."
+  if [ -f ".venv/bin/activate" ]; then
+    source .venv/bin/activate
path: deploy.sh
user: login: github-advanced-security[bot]
body: Not following: .venv/bin/activate: openBinaryFile: does not exist (No such file or directory)

[Show more details](https://github.com/ioannisioannides/scopewatch/security/code-scanning/424)
created_at: 2025-04-09T22:59:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,39 @@
+#!/bin/bash
+# Deployment script for Scopewatch
+# This script runs database migrations and collects static files
+
+set -e  # Exit immediately if a command exits with a non-zero status
+
+# Ensure we're in the project directory (where manage.py is located)
+cd "$(dirname "$0")"
+
+# Activate virtual environment if it exists
+if [ -d ".venv" ]; then
+  echo "Activating virtual environment..."
+  if [ -f ".venv/bin/activate" ]; then
+    source .venv/bin/activate
+  elif [ -f ".venv/Scripts/activate" ]; then
+    source .venv/Scripts/activate
path: deploy.sh
user: login: github-advanced-security[bot]
body: Not following: .venv/Scripts/activate: openBinaryFile: does not exist (No such file or directory)

[Show more details](https://github.com/ioannisioannides/scopewatch/security/code-scanning/425)
created_at: 2025-04-09T22:59:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,28 @@
+#!/bin/bash
+# Development launcher script for Scopewatch
+# This script sets up the development environment and starts the server
+
+# Ensure we're in the project directory
+cd "$(dirname "$0")"
path: dev.sh
user: login: github-advanced-security[bot]
body: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.

[Show more details](https://github.com/ioannisioannides/scopewatch/security/code-scanning/421)
created_at: 2025-04-09T22:59:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,28 @@
+#!/bin/bash
+# Development launcher script for Scopewatch
+# This script sets up the development environment and starts the server
+
+# Ensure we're in the project directory
+cd "$(dirname "$0")"
+
+# Create .env file from .env.development if it doesn't exist
+if [ ! -f ".env" ] && [ -f ".env.development" ]; then
+  echo "Creating .env file from .env.development..."
+  cp .env.development .env
+fi
+
+# Activate virtual environment if it exists
+if [ -d ".venv" ]; then
+  echo "Activating virtual environment..."
+  if [ -f ".venv/bin/activate" ]; then
+    source .venv/bin/activate
path: dev.sh
user: login: github-advanced-security[bot]
body: Not following: .venv/bin/activate: openBinaryFile: does not exist (No such file or directory)

[Show more details](https://github.com/ioannisioannides/scopewatch/security/code-scanning/423)
created_at: 2025-04-09T22:59:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,28 @@
+#!/bin/bash
+# Development launcher script for Scopewatch
+# This script sets up the development environment and starts the server
+
+# Ensure we're in the project directory
+cd "$(dirname "$0")"
+
+# Create .env file from .env.development if it doesn't exist
+if [ ! -f ".env" ] && [ -f ".env.development" ]; then
+  echo "Creating .env file from .env.development..."
+  cp .env.development .env
+fi
+
+# Activate virtual environment if it exists
+if [ -d ".venv" ]; then
+  echo "Activating virtual environment..."
+  if [ -f ".venv/bin/activate" ]; then
+    source .venv/bin/activate
+  elif [ -f ".venv/Scripts/activate" ]; then
+    source .venv/Scripts/activate
path: dev.sh
user: login: github-advanced-security[bot]
body: Not following: .venv/Scripts/activate: openBinaryFile: does not exist (No such file or directory)

[Show more details](https://github.com/ioannisioannides/scopewatch/security/code-scanning/422)
created_at: 2025-04-09T22:59:17Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-09T22:57:14Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: failure by coderabbit.ai -->

> [!CAUTION]
> ## Review failed
> 
> The pull request is closed.

<!-- end of auto-generated comment: failure by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
This pull request adds new environment configuration files for both development and production, updates GitHub Actions workflows and Docker configurations, and enhances environment variable handling. New scripts for deployment and development (including a management command to create or update a superuser) have been introduced to automate setup tasks. Additionally, the application configuration has been updated with helper functions to detect the running environment and adjust settings accordingly. Minor improvements in error handling and command execution were also applied in existing setup scripts.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `.env.development`, `.env.production` | Added new configuration files with key-value pairs for environment settings (ENV, DEBUG, DJANGO_SECRET_KEY, ALLOWED_HOSTS, DB_ENGINE); production file includes commented PostgreSQL settings. |
| `.github/workflows/ci-cd.yml`, `.github/workflows/dependency-review.yml` | Updated CI/CD workflow to use a variable Python version and added environment variables; removed a dependency submission step in the dependency review workflow. |
| `Dockerfile`, `Dockerfile.dev`, `docker-compose.prod.yml`, `docker-compose.yml` | Modified Dockerfiles to set new environment variables, install additional dependencies (gunicorn), and create necessary directories; updated Compose files to reference environment variables and added a new DATABASE_URL setting. |
| `apps/management/commands/create_or_update_superuser.py`, `deploy.sh`, `dev.sh`, `setup_dev_environment.py` | Introduced a new management command for creating/updating a superuser; added deployment and development scripts to automate migrations, static file collection, virtual environment activation, and server start; enhanced validation and error handling in setup scripts. |
| `scopewatch/config.py`, `scopewatch/settings.py` | Enhanced environment configuration by adding `is_production`, `is_development`, and updated logic for secret and SSL settings; updated installed apps to reference a specific management configuration. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    autonumber
    participant S as deploy.sh Script
    participant V as Virtual Environment
    participant M as Django Management
    participant G as Gunicorn Server

    S->>S: Set shell options and change working directory
    S->>V: Check and activate virtual environment
    S->>M: Run "python manage.py migrate"
    M-->>S: Migrations complete
    S->>M: Run "python manage.py collectstatic --noinput"
    M-->>S: Static files collected
    S->>M: Run "python manage.py create_or_update_superuser"
    M-->>S: Superuser processed
    S->>G: Attempt to start gunicorn
    G-->>S: Gunicorn server started (or error reported)
```

```mermaid
sequenceDiagram
    autonumber
    participant S as dev.sh Script
    participant F as Filesystem (.env)
    participant V as Virtual Environment
    participant M as Django Management

    S->>F: Check for .env file (copy from .env.development if missing)
    S->>V: Activate virtual environment (.venv presence)
    S->>M: Run "python manage.py migrate"
    M-->>S: Migrations complete
    S->>M: Run "python manage.py runserver"
    M-->>S: Development server started
```

## Poem
> I’m a rabbit tapping keys with glee,  
> Hopping through new files so sprightly and free.  
> Env files, scripts, and workflows in a row,  
> Deployments and setups now having a glow.  
> With every command and a well-set aim,  
> I celebrate these changes in the coding game! 🐇  
> Nibble on code and watch it grow!

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9fa5c22c653d9179804aa8291d76f11e1504635c and 9707a96787265202e0c7510fb0d72556c9c1e03d.

</details>

<details>
<summary>📒 Files selected for processing (14)</summary>

* `.env.development` (1 hunks)
* `.env.production` (1 hunks)
* `.github/workflows/ci-cd.yml` (3 hunks)
* `.github/workflows/dependency-review.yml` (0 hunks)
* `Dockerfile` (1 hunks)
* `Dockerfile.dev` (1 hunks)
* `apps/management/commands/create_or_update_superuser.py` (1 hunks)
* `deploy.sh` (1 hunks)
* `dev.sh` (1 hunks)
* `docker-compose.prod.yml` (1 hunks)
* `docker-compose.yml` (1 hunks)
* `scopewatch/config.py` (2 hunks)
* `scopewatch/settings.py` (3 hunks)
* `setup_dev_environment.py` (1 hunks)

</details>

</details>
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=ioannisioannides/scopewatch&utm_content=67):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-09T22:57:20Z
body: <h1>Dependency Review</h1>
✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.<h2>Scanned Files</h2>
<ul><li>.github/workflows/dependency-review.yml</li></ul>


<!-- dependency-review-pr-comment-marker -->
author_association: NONE