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
13 changes: 1 addition & 12 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
# Stage 1: Build frontend assets
FROM node:22-slim AS builder
RUN corepack enable
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build

# Stage 2: Production image
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY --from=builder /app/webapp ./webapp
COPY data ./data
COPY . .
CMD ["gunicorn", "--chdir", "webapp", "-b", "0.0.0.0:8000", "app:app"]
Comment on lines 3 to 6

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check requirements.txt exists and contains necessary packages
if [ -f requirements.txt ]; then
  echo "=== requirements.txt contents ==="
  cat requirements.txt
  echo ""
  echo "=== Checking for required packages ==="
  grep -E '(gunicorn|flask|werkzeug)' requirements.txt || echo "⚠ Missing required packages"
else
  echo "✗ requirements.txt not found"
fi

# Verify directory structure needed by app.py
echo ""
echo "=== Checking directory structure ==="
[ -d "data" ] && echo "✓ data/ directory exists" || echo "✗ data/ directory missing"
[ -d "webapp" ] && echo "✓ webapp/ directory exists" || echo "✗ webapp/ directory missing"
[ -f "scripts/out/status_list.txt" ] && echo "✓ scripts/out/status_list.txt exists" || echo "✗ scripts/out/status_list.txt missing (referenced in app.py:208)"

Repository: Hugo0/wordle

Length of output: 331


🏁 Script executed:

# Check if app.py creates the data/ directory or expects it to exist
grep -n "data" webapp/app.py | head -20

Repository: Hugo0/wordle

Length of output: 1256


Dockerfile requires data/ directory to be present for the app to start.

The requirements.txt is correctly configured with all necessary runtime dependencies (Flask, gunicorn, etc.). However, app.py attempts to load data files from data/ during startup (line 39 and beyond), and this directory is missing. The application will crash with a FileNotFoundError at runtime. Either add the data/ directory to the Docker image or copy it from the repository during the build.

🤖 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 `@Dockerfile` around lines 3 - 6, The Dockerfile currently copies
requirements.txt and the project root but doesn't ensure the runtime data
directory exists; because app.py (starting near line 39) loads files from data/
at startup, add the data directory into the image during build (e.g., update the
Dockerfile to COPY the repository data/ into the image or create an empty data/
and include required files) so that when CMD runs gunicorn and app:app, app.py
can find data/; modify the Dockerfile around the existing COPY . . step to
explicitly COPY data/ data/ (or create the directory and required fixtures) so
no FileNotFoundError occurs at startup.

5 changes: 5 additions & 0 deletions webapp/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
url_for,
request,
)

from werkzeug.middleware.proxy_fix import ProxyFix

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check werkzeug version in requirements.txt
echo "=== Checking werkzeug version ==="
grep -i werkzeug requirements.txt || echo "⚠ werkzeug not found in requirements.txt"

Repository: Hugo0/wordle

Length of output: 131


🏁 Script executed:

# Check if webapp/app.py exists and what's on line 10
if [ -f "webapp/app.py" ]; then
  echo "=== webapp/app.py line 10 ==="
  sed -n '10p' webapp/app.py
else
  echo "⚠ webapp/app.py not found"
fi

# Search for werkzeug in all common dependency files
echo ""
echo "=== Searching for werkzeug in all dependency files ==="
find . -maxdepth 2 -type f \( -name "setup.py" -o -name "pyproject.toml" -o -name "setup.cfg" -o -name "Pipfile" -o -name "poetry.lock" -o -name "requirements*.txt" \) -exec grep -l "werkzeug" {} \; 2>/dev/null || echo "werkzeug not found in any dependency file"

# Also check the actual content if found
echo ""
echo "=== Content of dependency files with werkzeug ==="
find . -maxdepth 2 -type f \( -name "setup.py" -o -name "pyproject.toml" -o -name "setup.cfg" -o -name "Pipfile" -o -name "poetry.lock" \) -exec sh -c 'grep -H "werkzeug" "$1" 2>/dev/null' _ {} \;

Repository: Hugo0/wordle

Length of output: 244


Add werkzeug as a project dependency.

ProxyFix is imported on line 10, but werkzeug is not declared in any dependency file (requirements.txt, setup.py, pyproject.toml, etc.). The application will fail at runtime if werkzeug is not installed. Add it to your dependency declaration with a compatible version (1.0+).

🤖 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 `@webapp/app.py` at line 10, The project imports ProxyFix from werkzeug in
app.py but werkzeug is not declared as a dependency; add werkzeug (version
>=1.0) to your project's dependency manifest (e.g., requirements.txt, setup.py
install_requires, or pyproject.toml [tool.poetry.dependencies] as appropriate)
so the runtime can install it, and run your dependency installer (pip install -r
requirements.txt or equivalent) to verify the app can import ProxyFix
successfully.


import json

import datetime
Expand All @@ -17,6 +20,8 @@

app = Flask(__name__)

app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make ProxyFix configuration conditional or document reverse proxy requirement.

Enabling ProxyFix unconditionally means the app will trust X-Forwarded-* headers from any client. If the app is accidentally exposed without a reverse proxy (e.g., during development or misconfiguration), clients can forge these headers to:

  • Bypass the HTTP→HTTPS redirect (line 352) by sending X-Forwarded-Proto: https
  • Manipulate request.url and url_for() results
🔒 Proposed fix: Make ProxyFix conditional on environment
+import os
+
 app = Flask(__name__)
 
-app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
+# Only enable ProxyFix when behind a reverse proxy
+if os.environ.get('BEHIND_PROXY', 'false').lower() == 'true':
+    app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

Then set BEHIND_PROXY=true in the production environment (Docker, systemd, etc.).

🤖 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 `@webapp/app.py` at line 23, The app currently unconditionally applies ProxyFix
via the statement app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1),
which trusts X-Forwarded-* headers; change this so ProxyFix is only applied when
an environment flag (e.g., BEHIND_PROXY=true) is set or when running in a
production config: check the env/config before wrapping app.wsgi_app and leave
it unwrapped by default, update any related startup docs to require
BEHIND_PROXY=true when the app is behind a reverse proxy, and ensure the
conditional preserves the same ProxyFix parameters (x_proto=1, x_host=1) when
enabled.


###############################################################################
# DATA
###############################################################################
Expand Down