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
60 changes: 42 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,75 @@ on:
- ci
- dev
- main
workflow_dispatch:

jobs:
ci:
name: Python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [3.7, 3.8, 3.9, "3.10", 3.11, 3.12, pypy3.9]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "pypy3.10"]

steps:
- uses: actions/checkout@v3
- name: setup python
uses: actions/setup-python@v4
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
cache-dependency-path: pyproject.toml
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .[dev]
pip install -e ".[test]" coveralls
- name: Run ruff
run: ruff check .
- name: Run test
run: coverage run --source=python_ipware -m unittest discover
- name: Run tests (modern default + router)
run: coverage run -m unittest discover -s tests -p "tests_*.py"
- name: Run frozen v3 tests against the legacy engine
run: python -m tests.legacy.run_against_legacy
- name: Coveralls
# Coverage upload is informational; a Coveralls outage must not fail CI.
continue-on-error: true
run: coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_FLAG_NAME: python-${{ matrix.python-version }}
COVERALLS_PARALLEL: true

coveralls-finish:
name: Coveralls finish
needs: ci
runs-on: ubuntu-latest
steps:
- name: Finish parallel coverage
uses: coverallsapp/github-action@v2
with:
parallel-finished: true
fail-on-error: false

build:
name: Build
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v4
- uses: actions/checkout@v5
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'
cache: 'pip'
python-version: "3.12"
cache: "pip"
cache-dependency-path: pyproject.toml
- name: Install build tools
run: pip3 --quiet install --upgrade build wheel
run: python -m pip install --upgrade build twine
- name: Build
run: python3 -m build .
- uses: actions/upload-artifact@v3
run: python -m build
- name: Check distribution metadata
run: python -m twine check dist/*
- uses: actions/upload-artifact@v4
with:
name: artifacts
path: dist/*
Expand All @@ -69,14 +93,14 @@ jobs:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
id-token: write # mandatory for trusted publishing
needs:
- build
- ci
steps:
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
name: artifacts
path: dist
- name: Publish build to PyPI
uses: pypa/gh-action-pypi-publish@v1.8.10
uses: pypa/gh-action-pypi-publish@release/v1
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
## 4.0.0

Community (thank you!):
- Trusted proxies in `proxy_list` can now be CIDR networks, IPv4 or IPv6 (e.g. `100.64.0.0/10`), matched by
real network membership; plain prefixes still work. Modern engine only. Requested by @griffi-gh (#26).
- Added Fly.io's `Fly-Client-IP` header to the modern default precedence. Suggested by @mdalp (#23).
- README now shows how to put a CDN header such as Cloudflare's first via `precedence`, when all traffic
comes through that CDN. Suggested by @iloveitaly (#25).
- CI covers Python 3.13 and newer. Suggested by @iloveitaly (#24).

Enhance:
- Introduce a pluggable algorithm router: `IpWare(algorithm=...)` with `"auto"` (default), `"modern"`, and `"legacy"`.
- `"auto"` resolves to `"modern"` — the enhanced engine and the forward-moving default.
- `"legacy"` is an explicit escape hatch that runs the frozen v3 algorithm byte-for-byte.
- New `modern` engine: hardened IPv6 / bracketed-port / IPv4-mapped parsing and an expanded default header
precedence list (adds `True-Client-IP`, `Fastly-Client-IP`, App Engine, Azure `X-Client-IP`).
- The frozen v3 algorithm is preserved unchanged under `python_ipware.legacy`; the original v3 test suite
passes against both the legacy and modern engines.

Modernize:
- Migrate packaging to PEP 621 with the Hatchling build backend; version is read from `__version__.py`.
- Drop end-of-life Python 3.7 / 3.8; requires Python 3.9+, tested on 3.9–3.14.
- Bump ruff config to the `lint.*` table layout.

Note:
- No source change is required for existing users: `from python_ipware import IpWare` continues to work and
now defaults to the modern engine. On well-formed headers modern returns the same result as v3 (the full
v3 suite and a legacy-vs-modern differential test pass). It differs only on malformed values:
- quoted addresses such as `"1.2.3.4"` are accepted (v3 ignored them);
- a value with more than one port-like suffix, such as `1.2.3.4:80:90`, is rejected (v3 took `1.2.3.4`).
Use `IpWare(algorithm="legacy")` if you depend on the exact v3 handling of those inputs.

## 3.0.0

Fix:
Expand Down
Loading
Loading