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
19 changes: 19 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.git
.github
.gitignore
.idea
.pytest_cache
__pycache__
**/__pycache__
*.pyc
venv
i-try
tests
example.gif
*.md
*.MD
LICENSE
CONTRIBUTING.md
tests.bat
# Never copy keys or certs into the image.
*.pem
37 changes: 37 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Minimum is 3.10: sanic 25.12.0 and markdown-it-py 4.0.0 both require >=3.10
# (and cryptography 46.0.3 excludes 3.9.0/3.9.1). 3.13 is the highest version
# supported across every pinned dependency.
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Run tests
run: pytest tests/ -v
30 changes: 0 additions & 30 deletions .github/workflows/django.yml

This file was deleted.

55 changes: 55 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Docker Publish

# Build and push a Docker image to GHCR on every version tag (v1.2.3, v2.0.0, ...).
on:
push:
tags:
- "v*"

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract image metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# Derive image tags from the git tag.
# v1.2.3 -> 1.2.3, 1.2, 1, plus a stable "latest".
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest

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

- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
33 changes: 33 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# syntax=docker/dockerfile:1
FROM python:3.13-slim

ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1 \
HOST=0.0.0.0 \
PORT=8000

WORKDIR /app

# Install dependencies first so this layer is cached unless requirements change.
# All pinned deps ship manylinux wheels, so no compiler toolchain is needed.
COPY requirements.txt ./
RUN python -m pip install --upgrade pip \
&& pip install -r requirements.txt

# Copy application source.
COPY cmd_chat ./cmd_chat
COPY cmd_chat.py ./
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

# Run as an unprivileged user.
RUN useradd --create-home --uid 10001 appuser
USER appuser

# Server listens on $PORT (default 8000).
EXPOSE 8000

# No password is baked into the image. PASSWORD must be supplied at run time:
# docker run -e PASSWORD=secret -p 8000:8000 ghcr.io/diorwave/cmd-chat:latest
ENTRYPOINT ["docker-entrypoint.sh"]
16 changes: 16 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env sh
set -e

# Host and port have safe defaults but can be overridden at run time.
: "${HOST:=0.0.0.0}"
: "${PORT:=8000}"

# The server password is a secret. It is never baked into the image; it must be
# provided at run time, for example:
# docker run -e PASSWORD=secret -p 8000:8000 ghcr.io/diorwave/cmd-chat:latest
if [ -z "${PASSWORD:-}" ]; then
echo "ERROR: PASSWORD environment variable is required (pass it at run time, e.g. -e PASSWORD=...)." >&2
exit 1
fi

exec python cmd_chat.py serve "$HOST" "$PORT" --password "$PASSWORD"
Binary file modified requirements.txt
Binary file not shown.
Loading