Skip to content
Merged
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
9 changes: 9 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.git/
.venv/
__pycache__/
.pytest_cache/
.mypy_cache/
docs/
.github/
README.md
.pre-commit-config.yaml
62 changes: 62 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: CI

on:
push:
branches:
- main
- develop
pull_request:
branches:
- main
- develop

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493
- uses: actions/setup-python@cfd55ca82492758d853442341ad4d8010466803a
with:
python-version: '3.12'
- name: Run pre-commit
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd

test:
needs: lint
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@cfd55ca82492758d853442341ad4d8010466803a
with:
python-version: ${{ matrix.python-version }}

- name: Install Poetry
uses: snok/install-poetry@ff8a7d7de27005376176819789742a2280cc35e2

- name: Configure Poetry
run: poetry config virtualenvs.in-project true

- name: Cache dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830
with:
path: .venv
key: v1-${{ runner.os }}-python-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }}
restore-keys: |
v1-${{ runner.os }}-python-${{ matrix.python-version }}-

- name: Install dependencies
run: poetry install --no-interaction --no-root

- name: Run tests
run: poetry run pytest
54 changes: 54 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Docker

on:
push:
branches:
- main
- develop

permissions:
contents: read
packages: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-scan-push:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493

- name: Log in to the Container registry
uses: docker/login-action@9788b0c4429711fb0def2b5cb23a4bB5Dff6c30a
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up QEMU
uses: docker/setup-qemu-action@68827325e0b33c7199093565ac3b62264dc64a97

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d70bba72b6f31a22640103738a088e5d3c8b4104

- name: Build and push
uses: docker/build-push-action@2cddeafc873d6113b789a7164923793f63101131
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Scan for vulnerabilities
uses: aquasecurity/trivy-action@678a23d8ab761c56f6f59508935c1054363d11b3
with:
image-ref: 'ghcr.io/${{ github.repository }}:${{ github.sha }}'
format: 'table'
exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'
84 changes: 11 additions & 73 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
*.py[cod]
*$py.class

# C extensions
Expand All @@ -20,7 +20,6 @@ parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
Expand All @@ -46,10 +45,9 @@ htmlcov/
nosetests.xml
coverage.xml
*.cover
*.py.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
Expand All @@ -72,7 +70,6 @@ instance/
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
Expand All @@ -83,48 +80,28 @@ 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
.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.
# from different sources is not a concern, Pipfile.lock also may be ignored.
#Pipfile.lock

# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.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
# This is especially true if you want to ensure deterministic builds.
# However, in some cases, it may be desirable to ignore them.
#poetry.lock
#poetry.toml

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
#pdm.lock
#pdm.toml
.pdm-python
.pdm-build/

# pixi
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
#pixi.lock
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
# in the .venv directory. It is recommended not to include this directory in version control.
.pixi

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
# pdm stores its cache in the specified location, which is ~/.pdm/cache by default.
# It might be desirable to ignore it if you use a different cache directory.
#.pdm-cache/

# PEP 582; used by pdm
__pypackages__/

# Celery stuff
Expand All @@ -136,7 +113,6 @@ celerybeat.pid

# Environments
.env
.envrc
.venv
env/
venv/
Expand Down Expand Up @@ -167,41 +143,3 @@ dmypy.json

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Abstra
# Abstra is an AI-powered process automation framework.
# Ignore directories containing user credentials, local state, and settings.
# Learn more at https://abstra.io/docs
.abstra/

# Visual Studio Code
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/

# Ruff stuff:
.ruff_cache/

# PyPI configuration file
.pypirc

# Cursor
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
# refer to https://docs.cursor.com/context/ignore-files
.cursorignore
.cursorindexingignore

# Marimo
marimo/_static/
marimo/_lsp/
__marimo__/
23 changes: 23 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-json
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.2
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.18.2
hooks:
- id: mypy
- repo: https://github.com/AleksaC/hadolint-py
rev: v2.14.0
hooks:
- id: hadolint
27 changes: 27 additions & 0 deletions CI_CD_STRATEGY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# CI/CD Strategy

This document outlines the CI/CD architecture for this project, including the Docker strategy and security measures.

## CI/CD Architecture

The CI/CD pipeline is built using GitHub Actions and is divided into two workflows: `ci.yml` and `docker.yml`.

- **`ci.yml`**: This workflow is triggered on `push` and `pull_request` events to the `main` and `develop` branches. It consists of two jobs:
1. **`lint`**: This job runs the `pre-commit` suite to ensure all code adheres to the defined quality and style standards.
2. **`test`**: This job runs the `pytest` suite across a matrix of Python versions (3.10, 3.11, and 3.12) to ensure the code is working as expected. It depends on the `lint` job, so it will only run if the linting passes.

- **`docker.yml`**: This workflow is triggered on `push` events to the `main` and `develop` branches. It builds, scans, and pushes a Docker image to the GitHub Container Registry.

## Docker Strategy

The `Dockerfile` is a multi-stage build to create a lean and secure production image.

- **Stage 1 (Builder)**: This stage installs Poetry, exports the project dependencies to a `requirements.txt` file, and installs them. It also installs the application itself.
- **Stage 2 (Runtime)**: This stage uses a slim Python base image, creates a non-root user, and copies the installed dependencies and application from the builder stage. This results in a smaller and more secure final image.

## Security Measures

- **Principle of Least Privilege (PoLP)**: The GitHub Actions workflows are configured with the minimum required permissions.
- **SHA Pinning**: All third-party GitHub Actions are pinned to their full commit SHA to prevent supply chain attacks.
- **Vulnerability Scanning**: The `docker.yml` workflow includes a step to scan the Docker image for vulnerabilities using Trivy. The workflow will fail if any `CRITICAL` or `HIGH` severity vulnerabilities are found.
- **Non-Root User**: The `Dockerfile` creates and runs the application as a non-root user to reduce the attack surface.
40 changes: 40 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Stage 1: Builder
FROM python:3.12-slim AS builder

# Install poetry
RUN pip install --no-cache-dir poetry==1.8.2

# Set the working directory
WORKDIR /app

# Copy the project files and install dependencies
COPY pyproject.toml poetry.lock* ./
COPY src/ ./src/

# Export dependencies and install them, then install the project
RUN poetry export -f requirements.txt --output requirements.txt --without-hashes && \
pip install --no-cache-dir --prefix="/install" -r requirements.txt && \
poetry install --no-dev


# Stage 2: Runtime
FROM python:3.12-slim AS runtime

# Create a non-root user
RUN useradd --create-home --shell /bin/bash appuser
USER appuser

# Add user's local bin to PATH
ENV PATH="/home/appuser/.local/bin:${PATH}"

# Set the working directory
WORKDIR /home/appuser/app

# Copy the installed dependencies from the builder stage
COPY --from=builder /install /usr/local

# Copy the application source code from the builder stage
COPY --from=builder /app/src/my_python_project ./my_python_project

# Set the PYTHONPATH to include the installed packages
ENV PYTHONPATH="/home/appuser/app"
Loading