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
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Generate a secure secret token, for example, by running:
# python -c 'import secrets; print(secrets.token_hex(32))'
API_TOKEN=your_secret_api_token_here
253 changes: 25 additions & 228 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,236 +1,33 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C# Build Dirs
csproj/bin/*
csproj/obj/*
# Environment variables
.env

# C extensions
*.so
# Python cache
__pycache__/
*.pyc
*.pyo
*.pyd

# Distribution / packaging
.Python
build/
develop-eggs/
src/python_redlines/data/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
# Build artifacts
/dist/
/build/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
# Virtual environment
.venv/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# AWS User-specific
.idea/**/aws.xml

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# SonarLint plugin
.idea/sonarlint/
env/

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# IDE and editor files
.idea/
.vscode/
*.swp
*.swo

# Editor-based Rest Client
.idea/httpRequests
# Hatch
/.hatch/
/src/python_redlines/bin
/src/python_redlines/dist

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
# C# build artifacts
/csproj/bin/
/csproj/obj/
38 changes: 38 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Use an official Python runtime as a parent image
FROM python:3.11-slim

# Set the working directory in the container
WORKDIR /app

# Install .NET SDK and other dependencies
RUN apt-get update && \
apt-get install -y wget && \
wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh && \
chmod +x ./dotnet-install.sh && \
./dotnet-install.sh --version 8.0.100 && \
rm dotnet-install.sh

# Add .dotnet to the PATH
ENV PATH="/root/.dotnet:$PATH"

# Copy files required for build
COPY pyproject.toml .
COPY hatch_run_build_hook.py .
COPY build_differ.py .
COPY src/python_redlines/__about__.py src/python_redlines/__about__.py
COPY csproj/ csproj/

# Install hatch
RUN pip install hatch

# Build the project (which includes running build_differ.py)
RUN hatch run default:build

# Copy the rest of the application code
COPY . .

# Expose the port the app runs on
EXPOSE 8000

# Start the API server
CMD ["hatch", "run", "api:start"]
Comment on lines +1 to +38

Choose a reason for hiding this comment

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

medium

The Dockerfile can be significantly optimized for a smaller image size and better security by using a multi-stage build. Currently, the final image includes the .NET SDK and other build-time dependencies, which are not required for running the application.

A multi-stage build would involve:

  1. A builder stage to install the .NET SDK, build the C# binaries, and then discard this environment.
  2. A final, clean python:3.11-slim stage that copies only the necessary application code and the compiled binaries from the builder stage.

This practice leads to smaller, more secure, and faster-deploying images. Additionally, it's a good practice to clean up the apt cache within the same RUN layer to further reduce image size by adding && rm -rf /var/lib/apt/lists/*.

Comment on lines +1 to +38
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical security issues: running as root and no multi-stage build.

The Dockerfile has several security and optimization issues:

  1. Runs as root: Container runs as root user (security risk)
  2. Single-stage build: Includes build tools in final image (bloat)
  3. No health check: Container health monitoring not configured
  4. Build-time network dependency: Downloads installer during build

Apply this diff to create a secure multi-stage build:

-# Use an official Python runtime as a parent image
-FROM python:3.11-slim
+# Multi-stage build for smaller, more secure images
+FROM python:3.11-slim AS builder
 
 # Set the working directory in the container
 WORKDIR /app
 
 # Install .NET SDK and other dependencies
 RUN apt-get update && \
     apt-get install -y wget && \
     wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh && \
     chmod +x ./dotnet-install.sh && \
     ./dotnet-install.sh --version 8.0.100 && \
-    rm dotnet-install.sh
+    rm dotnet-install.sh && \
+    apt-get clean && \
+    rm -rf /var/lib/apt/lists/*
 
 # Add .dotnet to the PATH
 ENV PATH="/root/.dotnet:$PATH"
 
 # Copy files required for build
 COPY pyproject.toml .
 COPY hatch_run_build_hook.py .
 COPY build_differ.py .
 COPY src/python_redlines/__about__.py src/python_redlines/__about__.py
 COPY csproj/ csproj/
 
 # Install hatch
 RUN pip install hatch
 
 # Build the project (which includes running build_differ.py)
 RUN hatch run default:build
 
+# Final stage - runtime image
+FROM python:3.11-slim
+
+WORKDIR /app
+
+# Create non-root user
+RUN groupadd -r appuser && useradd -r -g appuser appuser && \
+    chown -R appuser:appuser /app
+
+# Copy built artifacts from builder
+COPY --from=builder --chown=appuser:appuser /app/dist ./dist
+COPY --from=builder --chown=appuser:appuser /app/src ./src
+
 # Copy the rest of the application code
-COPY . .
+COPY --chown=appuser:appuser pyproject.toml .
+COPY --chown=appuser:appuser README.md .
+
+# Install runtime dependencies only
+RUN pip install --no-cache-dir hatch && \
+    pip install --no-cache-dir -e .
+
+# Switch to non-root user
+USER appuser
 
 # Expose the port the app runs on
 EXPOSE 8000
 
+# Add health check
+HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
+    CMD python -c "import httpx; httpx.get('http://localhost:8000/health', timeout=2)" || exit 1
+
 # Start the API server
 CMD ["hatch", "run", "api:start"]
🤖 Prompt for AI Agents
In Dockerfile lines 1-38, the image currently runs as root, performs build and
downloads installers in the final image, and lacks a HEALTHCHECK; convert to a
secure multi-stage build by creating a builder stage (use an official dotnet SDK
base like mcr.microsoft.com/dotnet/sdk:8.0 or include the dotnet installer in
build context so no external network fetch at build time), perform all apt
installs, dotnet and Python build steps and hatch build in that builder, produce
only the runtime artifacts into a minimal final stage based on python:3.11-slim
(no build tools), create a non-root user in the final stage and set USER to it,
copy only needed files from builder, install runtime-only Python deps with pip
--no-cache-dir, and add a HEALTHCHECK instruction to probe the application
endpoint; ensure no wget/dotnet installer downloads happen in the final stage
and remove build-time tools from the final image.

Loading