Skip to content

fix: improve production security and cross-platform compatibility#958

Open
Ananya44444 wants to merge 7 commits intoalphaonelabs:mainfrom
Ananya44444:security
Open

fix: improve production security and cross-platform compatibility#958
Ananya44444 wants to merge 7 commits intoalphaonelabs:mainfrom
Ananya44444:security

Conversation

@Ananya44444
Copy link
Contributor

@Ananya44444 Ananya44444 commented Feb 25, 2026

Related issues

Fixes #957

Checklist

  • Did you run the pre-commit? (If not, your PR will most likely not pass — please ensure it passes pre-commit)
  • Did you test the change? (Ensure you didn’t just prompt the AI and blindly commit — test the code and confirm it works)
  • [/] Added screenshots to the PR description (if applicable)

Changes Made
Security Improvements

SECRET_KEY Validation: Added production environment validation to prevent the use of insecure default SECRET_KEY
Variable Declaration Order: Fixed undefined variable error by moving ENVIRONMENT definition before its usage

2.Cross-Platform Compatibility

systemctl Restart Fix: Added platform detection to only attempt systemctl restart on Linux systems
Error Handling: Added proper exception handling and timeout for subprocess operations
Graceful Fallback: Non-Linux systems now log appropriate messages instead of crashing

Summary by CodeRabbit

  • Bug Fixes

    • Service restart is now platform-aware (runs only on supported systems), with clearer logging and error handling when restarts fail or are skipped, improving reliability and diagnostics.
  • Improvements

    • Startup configuration tightened: secret input is trimmed/normalized, prior defaults preserved outside production, and a non-empty secret is enforced in production to prevent unsafe startups.

Copilot AI review requested due to automatic review settings February 25, 2026 13:44
@github-actions github-actions bot added the files-changed: 2 PR changes 2 files label Feb 25, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds early ENVIRONMENT handling and production-time SECRET_KEY validation in web/settings.py. Updates web/views.py to perform service restarts only on Linux: resolve systemctl path, run restart with timeout, catch FileNotFoundError and TimeoutExpired, and log failures or skipped restarts.

Changes

Cohort / File(s) Summary
Settings / SECRET_KEY
web/settings.py
Introduce ENVIRONMENT; read and trim raw_secret_key, compute SECRET_KEY from trimmed input or fallback default; raise ValueError when ENVIRONMENT == "production" and SECRET_KEY is empty; reorder init so ENVIRONMENT/SECRET_KEY handling runs before DEBUG logic.
Service Restart / Cross-platform guard
web/views.py
Replace unconditional systemctl restart with Linux-only guarded logic: detect Linux, resolve systemctl path from expected locations, run restart with timeout, log non-zero exit codes and exceptions (FileNotFoundError, TimeoutExpired), and skip restart with a log on non-Linux. Minor whitespace change in system_status.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant App as Application
    participant OS as Host/OS
    participant Log as Logger

    Client->>App: trigger action that may restart service
    App->>App: determine platform (is_linux?)
    alt Linux
        App->>OS: resolve `/bin/systemctl` or other known paths
        App->>OS: run `systemctl restart education-website` (with timeout)
        OS-->>App: exit code or raise FileNotFoundError / TimeoutExpired
        alt success (exit code 0)
            App->>Log: log success
            App-->>Client: continue flow
        else failure (non-zero / exception)
            App->>Log: log error, rc, and exception details
            App-->>Client: continue flow (restart flagged failed)
        end
    else Non-Linux
        App->>Log: log "restart skipped on non-Linux"
        App-->>Client: continue flow without restart
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • A1L13N
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: production security improvements and cross-platform compatibility enhancements for SECRET_KEY validation and systemctl handling.
Linked Issues check ✅ Passed All coding requirements from issue #957 are addressed: SECRET_KEY production validation [#957], ENVIRONMENT declaration ordering [#957], and Linux-only systemctl with error handling [#957].
Out of Scope Changes check ✅ Passed All changes directly address the objectives in #957: SECRET_KEY validation, ENVIRONMENT ordering, and cross-platform systemctl handling. No unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses issue #957 by hardening production configuration and making the GitHub webhook deploy flow safer on non-Linux platforms, reducing crashes and preventing insecure production startups.

Changes:

  • Add a production-only validation requiring SECRET_KEY to be set via environment variable.
  • Move ENVIRONMENT initialization earlier to avoid use-before-definition during settings evaluation.
  • Gate systemctl restart to Linux and add basic exception/timeout handling for the restart step.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
web/views.py Adds OS detection and exception handling around systemctl restart during webhook-driven deploys.
web/settings.py Adds production validation for SECRET_KEY and reorders ENVIRONMENT definition to support that validation safely.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/settings.py`:
- Around line 53-57: In production, tighten SECRET_KEY validation: when
ENVIRONMENT == "production" read SECRET_KEY via env.str (avoid silently falling
back to the insecure default), trim and reject empty or whitespace-only values
and also explicitly reject the known insecure fallback string currently used; if
invalid, raise ValueError. Update the check around ENVIRONMENT, SECRET_KEY and
env.str to validate the trimmed value against "" and the insecure default
constant and raise an error so the app cannot start with an unsafe key.

In `@web/views.py`:
- Around line 1120-1127: The subprocess.run call currently uses check=False so
non-zero exit codes are ignored; update the logic around the subprocess.run(...)
that restarts the service to detect non-zero return codes (either set check=True
or inspect the CompletedProcess.returncode) and treat failures as deployment
errors by setting the ok flag to False and appending a descriptive message to
log_lines (include stdout/stderr from the CompletedProcess for diagnostics);
also keep existing except handlers for FileNotFoundError and TimeoutExpired but
ensure any non-zero returncode is logged and causes the handler to return a
failure response instead of marking deployment successful.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20cc175 and ed2adc9.

📒 Files selected for processing (2)
  • web/settings.py
  • web/views.py

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
web/settings.py (1)

53-61: ⚠️ Potential issue | 🟠 Major

Harden production SECRET_KEY validation to reject insecure default and normalize environment.

At Line [51], Line [57], and Line [61], production safety can still be bypassed: ENVIRONMENT is not normalized (e.g., "Production" / " production "), and the known insecure fallback key is still accepted if explicitly provided.

🔐 Proposed fix
+# Constants for reuse and lint compliance
+INSECURE_DEFAULT_SECRET_KEY = "django-insecure-5kyff0s@l_##j3jawec5@b%!^^e(j7v)ouj4b7q6kru#o#a)o3"
+PRODUCTION_SECRET_KEY_ERROR = "SECRET_KEY must be configured to a strong non-default value in production."
+
 # Debug settings - must be defined before SECRET_KEY validation
-ENVIRONMENT = env.str("ENVIRONMENT", default="development")
+ENVIRONMENT = env.str("ENVIRONMENT", default="development").strip().lower()
 
 # Read and validate SECRET_KEY with proper whitespace handling
 raw_secret_key = env.str("SECRET_KEY", default="")
 SECRET_KEY = raw_secret_key.strip() if raw_secret_key else ""
 
-if ENVIRONMENT == "production" and not SECRET_KEY:
-    raise ValueError("SECRET_KEY environment variable must be set in production")
+if ENVIRONMENT == "production" and (not SECRET_KEY or SECRET_KEY == INSECURE_DEFAULT_SECRET_KEY):
+    raise ValueError(PRODUCTION_SECRET_KEY_ERROR)
 
 if not SECRET_KEY:
-    SECRET_KEY = "django-insecure-5kyff0s@l_##j3jawec5@b%!^^e(j7v)ouj4b7q6kru#o#a)o3"
+    SECRET_KEY = INSECURE_DEFAULT_SECRET_KEY

As per coding guidelines **/*.py: Fix linting errors in code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/settings.py` around lines 53 - 61, Normalize ENVIRONMENT and SECRET_KEY
by stripping whitespace and using a case-insensitive check, and disallow the
known insecure fallback value: trim raw_secret_key into SECRET_KEY (SECRET_KEY =
raw_secret_key.strip() if raw_secret_key else ""), normalize ENVIRONMENT for
checks (e.g., env_normalized = ENVIRONMENT.strip().lower()), then when
env_normalized == "production" raise ValueError if not SECRET_KEY or if
SECRET_KEY equals the insecure default string (compare exact value after strip),
and finally avoid assigning the insecure default as a fallback when SECRET_KEY
is empty so the insecure literal is never accepted even if provided.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@web/settings.py`:
- Around line 53-61: Normalize ENVIRONMENT and SECRET_KEY by stripping
whitespace and using a case-insensitive check, and disallow the known insecure
fallback value: trim raw_secret_key into SECRET_KEY (SECRET_KEY =
raw_secret_key.strip() if raw_secret_key else ""), normalize ENVIRONMENT for
checks (e.g., env_normalized = ENVIRONMENT.strip().lower()), then when
env_normalized == "production" raise ValueError if not SECRET_KEY or if
SECRET_KEY equals the insecure default string (compare exact value after strip),
and finally avoid assigning the insecure default as a fallback when SECRET_KEY
is empty so the insecure literal is never accepted even if provided.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed2adc9 and 6178b33.

📒 Files selected for processing (2)
  • web/settings.py
  • web/views.py

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
web/settings.py (1)

51-61: ⚠️ Potential issue | 🟠 Major

Harden production SECRET_KEY validation to reject unsafe defaults and normalize ENVIRONMENT.

At Line [51]-Line [61], production can still start with the known insecure default SECRET_KEY, and ENVIRONMENT casing/whitespace can bypass the production guard. This also keeps the TRY003 lint violation at Line [58].

🔐 Proposed fix
+# Keep message as a named constant (Ruff TRY003) and centralize insecure fallback.
+PRODUCTION_SECRET_KEY_ERROR = "SECRET_KEY must be configured to a strong non-default value in production."
+INSECURE_DEFAULT_SECRET_KEY = "django-insecure-5kyff0s@l_##j3jawec5@b%!^^e(j7v)ouj4b7q6kru#o#a)o3"
+
 # Debug settings - must be defined before SECRET_KEY validation
-ENVIRONMENT = env.str("ENVIRONMENT", default="development")
+ENVIRONMENT = env.str("ENVIRONMENT", default="development").strip().lower()
 
 # Read and validate SECRET_KEY with proper whitespace handling
-raw_secret_key = env.str("SECRET_KEY", default="")
-SECRET_KEY = raw_secret_key.strip() if raw_secret_key else ""
+raw_secret_key = env.str("SECRET_KEY", default="").strip()
+SECRET_KEY = raw_secret_key
 
-if ENVIRONMENT == "production" and not SECRET_KEY:
-    raise ValueError("SECRET_KEY environment variable must be set in production")
+if ENVIRONMENT == "production" and (not SECRET_KEY or SECRET_KEY == INSECURE_DEFAULT_SECRET_KEY):
+    raise ValueError(PRODUCTION_SECRET_KEY_ERROR)
 
 if not SECRET_KEY:
-    SECRET_KEY = "django-insecure-5kyff0s@l_##j3jawec5@b%!^^e(j7v)ouj4b7q6kru#o#a)o3"
+    SECRET_KEY = INSECURE_DEFAULT_SECRET_KEY
As per coding guidelines `**/*.py`: Fix linting errors in code.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/settings.py` around lines 51 - 61, Normalize ENVIRONMENT (strip and
lower) and harden SECRET_KEY checks: trim raw_secret_key into SECRET_KEY, then
if ENVIRONMENT == "production" ensure SECRET_KEY is non-empty and not equal to
the known insecure default string (reject that value and raise ValueError); do
not fall back to the insecure default in production. Update references to
ENVIRONMENT, raw_secret_key, and SECRET_KEY accordingly so production cannot be
bypassed by casing/whitespace and the insecure default is never accepted.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@web/settings.py`:
- Around line 51-61: Normalize ENVIRONMENT (strip and lower) and harden
SECRET_KEY checks: trim raw_secret_key into SECRET_KEY, then if ENVIRONMENT ==
"production" ensure SECRET_KEY is non-empty and not equal to the known insecure
default string (reject that value and raise ValueError); do not fall back to the
insecure default in production. Update references to ENVIRONMENT,
raw_secret_key, and SECRET_KEY accordingly so production cannot be bypassed by
casing/whitespace and the insecure default is never accepted.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6178b33 and 6986419.

📒 Files selected for processing (2)
  • web/settings.py
  • web/views.py

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/views.py`:
- Around line 1123-1138: Replace the unsafe shutil.which("systemctl") usage and
narrow PATH trust by validating systemctl_path against a whitelist of trusted
absolute locations (e.g., /bin/systemctl, /usr/bin/systemctl) and fallback to a
safe default only if the file exists and is executable before calling
subprocess.run (the call that restarts "education-website"); also broaden the
except clause around the subprocess.run invocation to catch OSError (or
Exception subclasses like PermissionError) instead of only FileNotFoundError and
subprocess.TimeoutExpired, and ensure you still append the error to log_lines
and set ok = False on failure.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6986419 and f9842f7.

📒 Files selected for processing (1)
  • web/views.py

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/views.py`:
- Line 1133: The call to subprocess.run in the proc = subprocess.run(...)
expression is triggering Ruff S603; since this invocation uses trusted absolute
paths and constant args, add an inline Ruff noqa suppression on that expression
(e.g., append "# noqa: S603 - uses trusted absolute path and constant args" to
the line) so the linter is satisfied and include the brief rationale in the
comment; locate the subprocess.run usage in the web/views.py view and add the
inline suppression directly on that line.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f9842f7 and adee359.

📒 Files selected for processing (1)
  • web/views.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

files-changed: 2 PR changes 2 files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security Vulnerabilities and Cross-Platform Issues

3 participants