Skip to content

Commit 6776344

Browse files
committed
build: refuse PyPI packages uploaded less than 3 days ago
Defense against the recent wave of PyPI hijack attacks where attackers publish a malicious version and have a few hours before maintainers notice. Mirrors npm's `min-release-age=3` setting. - Set PIP_UPLOADED_PRIOR_TO=P3D at workflow level so all pip subprocesses (including those spawned from integration test venvs and `python -m build`) refuse PyPI artifacts younger than 3 days. - Pin pip>=26.1 in every explicit upgrade step. The relative-duration form `P3D` was added in pip 26.1 (April 2026); older pip silently ignores the env var instead of failing, so the bootstrap is safe. - Commit a repo-level pip.conf so local developers can opt in by pointing PIP_CONFIG_FILE at it. Known gap: the test job's tox-managed venvs install testing deps (pytest, pytest-cov, pytest-bdd) through pip seeded by virtualenv, which currently ships an older pip that does not honor the env var. Closing this fully would require either per-package tox config changes across 7 packages or a virtualenv bundle bump; deferred.
1 parent 45e77bf commit 6776344

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

.github/workflows/pythonpackage.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ name: Python package
22

33
on: [ push ]
44

5+
env:
6+
# Supply-chain protection: refuse PyPI packages uploaded less than 3 days ago.
7+
# Honored by pip>=26.1 (relative durations); silently ignored by older pip.
8+
PIP_UPLOADED_PRIOR_TO: "P3D"
9+
510
jobs:
611
test:
712
runs-on: ubuntu-22.04
@@ -41,7 +46,7 @@ jobs:
4146
- name: Install dependencies
4247
if: steps.filter.outputs.changes == 'true'
4348
run: |
44-
python -m pip install --upgrade pip
49+
python -m pip install --upgrade 'pip>=26.1'
4550
pip install tox tox-gh-actions
4651
- name: Run tox
4752
if: steps.filter.outputs.changes == 'true'
@@ -60,7 +65,7 @@ jobs:
6065

6166
- name: Install reporters-validator
6267
run: |
63-
python -m pip install --upgrade pip
68+
python -m pip install --upgrade 'pip>=26.1'
6469
pip install git+https://github.com/qase-tms/reporters-validator.git
6570
6671
- name: Download report schemas
@@ -69,6 +74,7 @@ jobs:
6974
- name: Validate Pytest reporter
7075
run: |
7176
python -m venv /tmp/venv-pytest
77+
/tmp/venv-pytest/bin/python -m pip install --upgrade 'pip>=26.1'
7278
/tmp/venv-pytest/bin/pip install -q \
7379
./qase-api-client ./qase-api-v2-client ./qase-python-commons ./qase-pytest
7480
@@ -84,6 +90,7 @@ jobs:
8490
- name: Validate Behave reporter
8591
run: |
8692
python -m venv /tmp/venv-behave
93+
/tmp/venv-behave/bin/python -m pip install --upgrade 'pip>=26.1'
8794
/tmp/venv-behave/bin/pip install -q \
8895
./qase-api-client ./qase-api-v2-client ./qase-python-commons ./qase-behave
8996
@@ -101,6 +108,7 @@ jobs:
101108
- name: Validate Robot Framework reporter
102109
run: |
103110
python -m venv /tmp/venv-robot
111+
/tmp/venv-robot/bin/python -m pip install --upgrade 'pip>=26.1'
104112
/tmp/venv-robot/bin/pip install -q \
105113
./qase-api-client ./qase-api-v2-client ./qase-python-commons ./qase-robotframework \
106114
robotframework
@@ -119,6 +127,7 @@ jobs:
119127
- name: Validate Tavern reporter
120128
run: |
121129
python -m venv /tmp/venv-tavern
130+
/tmp/venv-tavern/bin/python -m pip install --upgrade 'pip>=26.1'
122131
/tmp/venv-tavern/bin/pip install -q \
123132
./qase-api-client ./qase-api-v2-client ./qase-python-commons ./qase-tavern \
124133
tavern
@@ -161,7 +170,7 @@ jobs:
161170
- name: Install build dependencies
162171
if: contains(github.event.ref, matrix.prefix)
163172
run: |
164-
python -m pip install --upgrade pip setuptools wheel build
173+
python -m pip install --upgrade 'pip>=26.1' setuptools wheel build
165174
- name: Build the package
166175
if: contains(github.event.ref, matrix.prefix)
167176
working-directory: ./${{ matrix.prefix }}

pip.conf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Supply-chain protection: refuse PyPI packages uploaded less than 3 days ago.
2+
# Defends against hijack attacks where a malicious version is published and
3+
# stays unnoticed for a few hours.
4+
#
5+
# Requires pip>=26.1 (relative durations). Older pip silently ignores this key.
6+
#
7+
# To activate for local development, point pip at this file:
8+
# export PIP_CONFIG_FILE=$(git rev-parse --show-toplevel)/pip.conf
9+
[global]
10+
uploaded-prior-to = P3D

0 commit comments

Comments
 (0)