diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-15 14:56:35 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-15 14:56:35 +0200 |
| commit | 7fc2fa04d7d88a1cdf0d290ddd2de3815a7d52a5 (patch) | |
| tree | c2ca93040bb95f5bcb667846a2fa91ddf0dd99bb /packages/meshbay-node/tests/test_packaging_audit.py | |
| parent | 9dd6d1003cf92c0e4e7f23414565314691aa5516 (diff) | |
| download | meshbay-7fc2fa04d7d88a1cdf0d290ddd2de3815a7d52a5.tar.gz | |
build: audit the shipped Python dependencies with pip-audit
No lock file pins the dependencies, so each build installs the newest
releases and what ships is only known once it has. packaging/audit_deps.py
runs pip-audit then: build-common.sh on the venv before stripping it,
build-node-runtime.ps1 on the environment before PyInstaller freezes it.
A known vulnerability stops the build, unless its id is listed in
packaging/pip-audit-ignore.txt with why it does not apply. No network only
skips the audit with a warning, as does a pip-audit that cannot be installed
or writes no report. pip-audit runs from a venv of its own, never from the
one that ships. Our packages are not audited (not on PyPI), nor pip,
setuptools and wheel, which do not ship.
Checked with the real build-common.sh (79 packages, none known), with
PyJWT 2.14 (the build stops on its two advisories, and goes on once they are
listed) and offline (a warning, the build goes on). The PowerShell step was
not run here.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/tests/test_packaging_audit.py')
| -rw-r--r-- | packages/meshbay-node/tests/test_packaging_audit.py | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/packages/meshbay-node/tests/test_packaging_audit.py b/packages/meshbay-node/tests/test_packaging_audit.py new file mode 100644 index 0000000..4409b01 --- /dev/null +++ b/packages/meshbay-node/tests/test_packaging_audit.py @@ -0,0 +1,64 @@ +""" +packaging/audit_deps.py, the pip-audit step of the builds. + +What can be checked without the network: a build with no network goes on +(the audit is skipped with a warning, never a failure), what is audited is +what ships, and the ignore list is read as ids. Whether pip-audit stops a +build on a real advisory needs the network and was checked by hand. +""" + +import importlib.util +import os +import subprocess +import sys +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[3] +SCRIPT = ROOT / "packaging" / "audit_deps.py" + +pytestmark = pytest.mark.skipif(not SCRIPT.exists(), reason="packaging not present") + + +def _module(): + spec = importlib.util.spec_from_file_location("audit_deps", SCRIPT) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + + +def test_no_network_skips_the_audit_without_failing_the_build(tmp_path): + # A proxy nobody listens on: every request is refused at once. + dead = "http://127.0.0.1:9" + env = {**os.environ, "HTTPS_PROXY": dead, "https_proxy": dead, + "HTTP_PROXY": dead, "http_proxy": dead} + run = subprocess.run([sys.executable, str(SCRIPT), "--tool-dir", str(tmp_path / "t")], + capture_output=True, text=True, env=env, timeout=60) + assert run.returncode == 0, run.stderr + assert "pip-audit skipped: no network" in run.stderr + assert not (tmp_path / "t").exists(), "nothing is installed when it cannot run" + + +def test_what_is_audited_is_what_ships(): + names = {line.split("==")[0].lower() for line in _module().shipped()} + assert "pytest" in names, "the environment's packages are listed" + assert not {n for n in names if n.startswith("meshbay")}, "ours are not on PyPI" + assert not names & {"pip", "setuptools", "wheel"}, "build tools do not ship" + + +def test_the_ignore_list_is_read_as_ids(tmp_path, monkeypatch): + mod = _module() + f = tmp_path / "ignore.txt" + f.write_text("# a comment\n\nPYSEC-2026-1 # not reached: no JWK import\n" + "GHSA-xxxx-yyyy-zzzz\n", encoding="utf-8") + monkeypatch.setattr(mod, "IGNORE_FILE", f) + assert mod.ignored() == ["PYSEC-2026-1", "GHSA-xxxx-yyyy-zzzz"] + + +def test_the_shipped_ignore_list_lets_nothing_through_unexplained(): + """Every id in the real file carries its reason.""" + mod = _module() + for line in mod.IGNORE_FILE.read_text(encoding="utf-8").splitlines(): + if line.strip() and not line.lstrip().startswith("#"): + assert "#" in line, f"no reason given: {line!r}" |