Compare commits

...

9 Commits

Author SHA1 Message Date
user 0ae7b13407 docs: clarify tor_nodes overrides listener first hop
ci / secrets (push) Successful in 5s
ci / test (push) Successful in 19s
ci / build (push) Failing after 28s
The first hop in each listener's chain is replaced at connection time
by round-robin selection from tor_nodes. Added comments in both the
example config and the server code to make this precedence explicit.
2026-02-22 16:42:20 +01:00
user a1996b1c9e fix: raise pool test_timeout and max_fails defaults
Accommodate HTTP CONNECT proxies through Tor (p99 latency >8s) and
reduce pool erosion when the upstream proxy count is low.

- test_timeout: 8 -> 12 (Tor + HTTP CONNECT overhead)
- max_fails: 3 -> 5 (10 min tolerance vs 6 min)
2026-02-22 16:39:55 +01:00
user 051c0ac719 fix: use podman --remote for builds via host socket
ci / secrets (push) Successful in 6s
ci / test (push) Successful in 21s
ci / build (push) Successful in 43s
Building images inside an unprivileged container fails on remount.
Use podman --remote with the runner-mounted podman socket to
delegate builds to the host engine.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:39:19 +01:00
user b4cf4fc8ae fix: write vfs storage config to system path for root podman
ci / secrets (push) Successful in 6s
ci / test (push) Successful in 20s
ci / build (push) Failing after 29s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:35:25 +01:00
user 251d99795b fix: use vfs storage driver for podman-in-container builds
ci / secrets (push) Successful in 6s
ci / test (push) Successful in 21s
ci / build (push) Failing after 24s
Runner ignores --privileged, so overlay mounts fail inside the
container. Switch to vfs storage driver via containers config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:11:42 +01:00
user cca76d4974 fix: add gitleaks allowlist for docs/tests false positives
ci / secrets (push) Successful in 5s
ci / test (push) Successful in 20s
ci / build (push) Failing after 33s
All 11 findings are API endpoint URLs (http://api:8081/...) in
documentation and test files, not actual secrets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:09:46 +01:00
user a64b09de8e fix: run CI jobs in rootless podman containers
ci / secrets (push) Failing after 6s
ci / test (push) Successful in 21s
ci / build (push) Has been skipped
Use container: directive per job instead of nested podman run.
Each job specifies its execution image directly:
- test: python:3.13-alpine
- secrets: ghcr.io/gitleaks/gitleaks:latest
- build: quay.io/podman/stable (--privileged for nested builds)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:08:55 +01:00
user de5f586bc7 fix: replace actions/checkout with git clone (no node on runner)
ci / test (push) Failing after 0s
ci / secrets (push) Failing after 0s
ci / build (push) Has been skipped
The linux runner has no Node.js, so actions/checkout@v4 fails.
Use manual git clone with token auth instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 06:54:18 +01:00
user 3e2c431f49 feat: switch CI to linux runner with podman containers
ci / test (push) Failing after 2s
ci / secrets (push) Failing after 2s
ci / build (push) Has been skipped
Replace ubuntu-latest runner with linux label and migrate all
container operations from docker to podman. Add requirements.txt
as single source of truth for runtime dependencies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 06:33:32 +01:00
6 changed files with 46 additions and 30 deletions
+25 -20
View File
@@ -6,38 +6,43 @@ on:
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: linux
container: python:3.13-alpine
steps: steps:
- uses: actions/checkout@v4 - run: apk add --no-cache git
- uses: actions/setup-python@v5 - run: |
with: git clone --depth 1 \
python-version: '3.13' -c "http.extraHeader=Authorization: token ${{ github.token }}" \
- run: pip install pyyaml ruff pytest "${{ github.server_url }}/${{ github.repository }}.git" .
- run: pip install --no-cache-dir -r requirements.txt ruff pytest
- run: ruff check src/ tests/ - run: ruff check src/ tests/
- run: PYTHONPATH=src pytest tests/ -v - run: PYTHONPATH=src pytest tests/ -v
secrets: secrets:
runs-on: ubuntu-latest runs-on: linux
container: ghcr.io/gitleaks/gitleaks:latest
steps: steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: | - run: |
docker run --rm \ git clone \
-v "$PWD:/scan:ro" \ -c "http.extraHeader=Authorization: token ${{ github.token }}" \
ghcr.io/gitleaks/gitleaks:latest \ "${{ github.server_url }}/${{ github.repository }}.git" .
detect --source /scan -v - run: gitleaks detect --source . -v
build: build:
needs: [test, secrets] needs: [test, secrets]
runs-on: ubuntu-latest runs-on: linux
container: quay.io/podman/stable
env:
CONTAINER_HOST: unix:///var/run/docker.sock
steps: steps:
- uses: actions/checkout@v4 - run: dnf install -y git
- run: | - run: |
mkdir -p ~/.docker git clone --depth 1 \
AUTH=$(printf '%s:%s' "$HARBOR_USER" "$HARBOR_PASS" | base64 -w0) -c "http.extraHeader=Authorization: token ${{ github.token }}" \
printf '{"auths":{"harbor.mymx.me":{"auth":"%s"}}}\n' "$AUTH" > ~/.docker/config.json "${{ github.server_url }}/${{ github.repository }}.git" .
- run: echo "$HARBOR_PASS" | podman --remote login -u "$HARBOR_USER" --password-stdin harbor.mymx.me
env: env:
HARBOR_USER: ${{ secrets.HARBOR_USER }} HARBOR_USER: ${{ secrets.HARBOR_USER }}
HARBOR_PASS: ${{ secrets.HARBOR_PASS }} HARBOR_PASS: ${{ secrets.HARBOR_PASS }}
- run: docker build --push -t harbor.mymx.me/s5p/s5p:latest -f Containerfile . - run: podman --remote build -t harbor.mymx.me/s5p/s5p:latest -f Containerfile .
- run: podman --remote push harbor.mymx.me/s5p/s5p:latest
+5
View File
@@ -0,0 +1,5 @@
[allowlist]
paths = [
'''tests/''',
'''docs/''',
]
+4 -3
View File
@@ -1,10 +1,11 @@
FROM python:3.13-alpine FROM python:3.13-alpine
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir pyyaml>=6.0
WORKDIR /app WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt
ENV PYTHONUNBUFFERED=1 \ ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \ PYTHONDONTWRITEBYTECODE=1 \
PYTHONPATH=/app/src PYTHONPATH=/app/src
+10 -7
View File
@@ -32,8 +32,8 @@ chain:
# state_file: /data/pool-clean.json # state_file: /data/pool-clean.json
# refresh: 300 # refresh: 300
# test_interval: 120 # test_interval: 120
# test_timeout: 8 # test_timeout: 12
# max_fails: 3 # max_fails: 5
# mitm: # MITM-capable proxies # mitm: # MITM-capable proxies
# sources: # sources:
# - url: http://10.200.1.250:8081/proxies/all # - url: http://10.200.1.250:8081/proxies/all
@@ -41,8 +41,8 @@ chain:
# state_file: /data/pool-mitm.json # state_file: /data/pool-mitm.json
# refresh: 300 # refresh: 300
# test_interval: 120 # test_interval: 120
# test_timeout: 8 # test_timeout: 12
# max_fails: 3 # max_fails: 5
# Single proxy pool (legacy, still supported -- becomes pool "default"): # Single proxy pool (legacy, still supported -- becomes pool "default"):
# proxy_pool: # proxy_pool:
@@ -75,8 +75,11 @@ chain:
# newnym_interval: 0 # periodic NEWNYM (seconds, 0 = manual only) # newnym_interval: 0 # periodic NEWNYM (seconds, 0 = manual only)
# Multi-Tor round-robin -- distribute traffic across multiple Tor nodes. # Multi-Tor round-robin -- distribute traffic across multiple Tor nodes.
# When present, the first hop in each listener's chain is replaced at # When present, the first hop in each listener's chain is REPLACED at
# connection time by round-robin selection from this list. # connection time by round-robin selection from this list. The first hop
# specified in each listener's chain acts as a fallback only; tor_nodes
# takes precedence for both client traffic and pool health tests.
# Connection pools are pre-warmed for every node listed here.
# tor_nodes: # tor_nodes:
# - socks5://10.200.1.1:9050 # - socks5://10.200.1.1:9050
# - socks5://10.200.1.254:9050 # - socks5://10.200.1.254:9050
@@ -110,7 +113,7 @@ chain:
# - localhost # exact hostname # - localhost # exact hostname
# - .local # domain suffix # - .local # domain suffix
# chain: # chain:
# - socks5://127.0.0.1:9050 # - socks5://127.0.0.1:9050 # first hop (overridden by tor_nodes)
# - [pool:clean, pool:mitm] # random choice per connection # - [pool:clean, pool:mitm] # random choice per connection
# - [pool:clean, pool:mitm] # independent random choice # - [pool:clean, pool:mitm] # independent random choice
# #
+1
View File
@@ -0,0 +1 @@
pyyaml>=6.0
+1
View File
@@ -208,6 +208,7 @@ async def _handle_client(
else: else:
effective_chain = list(listener.chain) effective_chain = list(listener.chain)
fhp = first_hop_pool fhp = first_hop_pool
# tor_nodes round-robin overrides the listener's first hop
if tor_rr and effective_chain: if tor_rr and effective_chain:
node = tor_rr.next() node = tor_rr.next()
effective_chain[0] = node effective_chain[0] = node