From 8c99544e3427fb159ed1e94ccb54d282d107038e Mon Sep 17 00:00:00 2001 From: user Date: Sat, 21 Feb 2026 17:18:14 +0100 Subject: [PATCH] feat: add Gitea CI workflow and production Containerfile Bake source into the image (COPY src/) so production containers run without volume mounts. CI pipeline runs ruff + pytest then builds and pushes harbor.mymx.me/s5p/s5p:latest on push to main. Co-Authored-By: Claude Opus 4.6 --- .containerignore | 9 +++++++++ .gitea/workflows/ci.yaml | 31 +++++++++++++++++++++++++++++++ Containerfile | 2 ++ PROJECT.md | 8 ++++++-- README.md | 9 +++++++-- TASKS.md | 2 ++ docs/CHEATSHEET.md | 12 +++++++++++- docs/INSTALL.md | 5 +++-- 8 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 .containerignore create mode 100644 .gitea/workflows/ci.yaml diff --git a/.containerignore b/.containerignore new file mode 100644 index 0000000..dcb3b7a --- /dev/null +++ b/.containerignore @@ -0,0 +1,9 @@ +.venv/ +.git/ +tests/ +docs/ +*.prof +*.egg-info/ +__pycache__/ +.gitea/ +.pytest_cache/ diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml new file mode 100644 index 0000000..1cba5ee --- /dev/null +++ b/.gitea/workflows/ci.yaml @@ -0,0 +1,31 @@ +name: ci + +on: + push: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + container: + image: python:3.13-slim + steps: + - uses: actions/checkout@v4 + - run: pip install pyyaml ruff pytest + - run: ruff check src/ tests/ + - run: PYTHONPATH=src pytest tests/ -v + + build: + needs: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: | + docker login harbor.mymx.me \ + -u "${{ secrets.HARBOR_USER }}" \ + -p "${{ secrets.HARBOR_PASS }}" + - run: | + docker build \ + -t harbor.mymx.me/s5p/s5p:latest \ + -f Containerfile . + - run: docker push harbor.mymx.me/s5p/s5p:latest diff --git a/Containerfile b/Containerfile index 6848329..865a53c 100644 --- a/Containerfile +++ b/Containerfile @@ -8,6 +8,8 @@ ENV PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONPATH=/app/src +COPY src/ /app/src/ + EXPOSE 1080 STOPSIGNAL SIGTERM diff --git a/PROJECT.md b/PROJECT.md index 19f5ab0..bee1f19 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -37,9 +37,13 @@ Client -------> s5p -------> Hop 1 -------> Hop 2 -------> Target | Local venv | `pip install -e .` then `s5p -c config/s5p.yaml` | | Container | `make build && make up` (Alpine, ~59MB) | -Container mounts `./src` and `./config/s5p.yaml` read-only, plus +Production images bake source into the image via `COPY src/ /app/src/`. +Config and data are mounted at runtime: `./config/s5p.yaml` (ro) and `~/.cache/s5p` as `/data` for pool state and profile output. -No application code is baked into the image. +The compose.yaml volume mount overrides source for local dev. + +CI pushes `harbor.mymx.me/s5p/s5p:latest` on every push to `main` +(lint + tests must pass first). ## Dependencies diff --git a/README.md b/README.md index 9cb6980..5cd117d 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,13 @@ make logs # podman-compose logs -f make down # podman-compose down ``` -Source, config, and data are bind-mounted, not baked into the image. -Pool state and profile output persist in `~/.cache/s5p/` (`/data` inside container). +Production images bake source into the image. Config and data are mounted +at runtime. Pool state and profile output persist in `~/.cache/s5p/` +(`/data` inside container). The compose.yaml volume mount overrides +source for local dev. + +CI (Gitea Actions) runs lint + tests on push to `main`, then builds and +pushes `harbor.mymx.me/s5p/s5p:latest`. ## Configuration diff --git a/TASKS.md b/TASKS.md index d5c1b10..41e94e9 100644 --- a/TASKS.md +++ b/TASKS.md @@ -65,6 +65,8 @@ - [x] Onion chain-only routing (.onion skips pool hops) - [x] Graceful shutdown timeout (fixes cProfile data dump) +- [x] Gitea CI workflow (lint + test + Harbor image push) + ## Next - [x] Integration tests with mock proxy server - [ ] SOCKS5 server-side authentication diff --git a/docs/CHEATSHEET.md b/docs/CHEATSHEET.md index 65df954..1207c23 100644 --- a/docs/CHEATSHEET.md +++ b/docs/CHEATSHEET.md @@ -30,7 +30,17 @@ make logs # podman-compose logs -f make down # podman-compose down ``` -Volumes: `./src` (ro), `./config/s5p.yaml` (ro), `~/.cache/s5p` → `/data` (pool state + profiles) +Volumes: `./config/s5p.yaml` (ro), `~/.cache/s5p` → `/data` (pool state + profiles) +Dev override: compose.yaml mounts `./src` (ro) over the baked-in source. + +## CI + +Gitea Actions runs on push to `main`: + +1. `ruff check` + `pytest` in `python:3.13-slim` +2. Build + push `harbor.mymx.me/s5p/s5p:latest` + +Secrets: `HARBOR_USER` / `HARBOR_PASS` (configured in Gitea repo settings). ## Config diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 5dbf39d..71ae3df 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -38,8 +38,9 @@ make build # podman-compose build make up # podman-compose up -d ``` -The Alpine-based image (~59MB) contains only Python and PyYAML. -Application source and config are bind-mounted at runtime. +The Alpine-based image (~59MB) contains Python, PyYAML, and baked-in +source. Config is mounted at runtime. The compose.yaml volume mount +overrides source for local dev. ## Install Tor (optional)