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
18 changes: 14 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,18 @@ jobs:
run: ./scripts/lock_requirements.ps1 -Check

pytest:
name: ${{ matrix.check_name }}
runs-on: ubuntu-24.04
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- python_version: '3.14'
check_name: pytest
- python_version: '3.11'
check_name: pytest (Python 3.11 minimum)
env:
TEST_REDIS_URL: redis://localhost:6379/15
services:
Expand All @@ -59,8 +68,8 @@ jobs:
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
# Mirror the runtime version shipped in the Docker image.
python-version: '3.11'
# Test both the production runtime and documented minimum version.
python-version: ${{ matrix.python_version }}
cache: pip
cache-dependency-path: |
requirements.txt
Expand Down Expand Up @@ -132,7 +141,7 @@ jobs:
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
# Mirror the runtime version shipped in the Docker image.
python-version: '3.11'
python-version: '3.14'
cache: pip
cache-dependency-path: |
requirements.txt
Expand All @@ -157,7 +166,8 @@ jobs:
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
# Mirror the runtime version shipped in the Docker image.
python-version: '3.14'
cache: pip
cache-dependency-path: |
requirements.txt
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.11-slim@sha256:db3ff2e1800a8581e2c48a27c3995339d47bdf046da21c7627accd3d51053a93
FROM python:3.14-slim@sha256:cea0e6040540fb2b965b6e7fb5ffa00871e632eef63719f0ea54bca189ce14a6

ARG VCS_REF=unknown

Expand Down
41 changes: 41 additions & 0 deletions tests/test_dependency_policy.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import re
from pathlib import Path

import pytest
Expand All @@ -11,6 +12,8 @@
"python -m pip install --require-hashes -r requirements-test.txt"
)
ALLOWED_PIP_LINES = {"cache: pip", APPROVED_PIP_INSTALL_COMMAND}
MINIMUM_PYTHON = "3.11"
PRODUCTION_PYTHON = "3.14"


def pip_policy_allows(workflow):
Expand All @@ -25,6 +28,15 @@ def pip_policy_allows(workflow):
)


def workflow_job(workflow, job_name):
marker = f"\n {job_name}:\n"
_, separator, remainder = workflow.partition(marker)
assert separator, f"missing workflow job: {job_name}"

next_job = re.search(r"(?m)^ [a-zA-Z0-9_-]+:\s*$", remainder)
return remainder[:next_job.start()] if next_job else remainder


def normalized_names(path):
return {
canonicalize_name(line.split("=", 1)[0].split("<", 1)[0].split(">", 1)[0])
Expand Down Expand Up @@ -147,6 +159,35 @@ def test_lock_generator_compiles_universal_locks():
assert "--universal" in script


def test_python_runtime_contract_stays_synchronized():
dockerfile = Path("Dockerfile").read_text(encoding="utf-8")
workflow = Path(".github/workflows/tests.yml").read_text(encoding="utf-8")
readme = Path("README.md").read_text(encoding="utf-8")

pytest_job = workflow_job(workflow, "pytest")
matrix_entries = re.findall(
r"- python_version: '([^']+)'\s+check_name: ([^\n]+)",
pytest_job,
)

assert dockerfile.startswith(
f"FROM python:{PRODUCTION_PYTHON}-slim@sha256:"
)
assert matrix_entries == [
(PRODUCTION_PYTHON, "pytest"),
(MINIMUM_PYTHON, f"pytest (Python {MINIMUM_PYTHON} minimum)"),
]
assert "python-version: ${{ matrix.python_version }}" in pytest_job

for job_name in ("ssh-integration", "browser-e2e"):
assert (
f"python-version: '{PRODUCTION_PYTHON}'"
in workflow_job(workflow, job_name)
)

assert f"python-{MINIMUM_PYTHON}+" in readme


def test_ci_installs_only_hash_checked_python_dependencies():
workflow = Path(".github/workflows/tests.yml").read_text(encoding="utf-8")

Expand Down
Loading