utils/dep_freshness/tests/test_quarantine.py
Krzysztof kuhy Rudnicki 1439c0f5c0 Make the allowlist inheritable, and cache the quarantine lookups
Two things that were fine in utils and would not have been in the next forty
repos.

**The allowlist is now fleet-wide plus per-repo.** `typescript-eslint` blocks
TS 7 in EVERY repo that pins typescript -- eight of them and counting -- and a
repo-only allowlist meant hand-copying one entry into eight files that then rot
independently. That is the four-way fork of the 250-line cap, reproduced inside
the mechanism built to avoid it. `~/utils/dependency-freshness.allowlist.yaml`
is inherited by every repo; a repo entry for the same `ecosystem:package`
overrides it.

Inherited entries are exempt from the no-longer-needed check everywhere except
the repo that owns the file. Without that carve-out a fleet-wide hold on
typescript exits 2 in every Flutter app -- it excuses nothing there, which is
the normal case, not rot -- and those repos become uncommittable. Confirmed
against punchme, which now exits 0 while utils still reports the entry as in
use.

**`quarantine.py` bypassed the cache entirely.** It ran for every npm finding
and fetched the FULL packument -- 7MB for react, 16MB for typescript -- with no
TTL and no reuse, inside a pre-commit hook. One finding in utils, but the JS
repos ahead have 16 to 37 each. Now cached under the normal 6h TTL, keyed
`<name>@<dist-tag>`: the tag has to be part of the key rather than clamped
afterwards, because clamping returns the ceiling and the ceiling is frequently
the very release the quarantine is excluding.

**Both cache and shared allowlist are now redirected by AUTOUSE fixtures.** A
quarantine test had already seeded a fake answer for package "x" into the real
~/.cache/dep-freshness/registry.json, and the next run read its own pollution
back and passed for the wrong reason. Removed the entry; the fixture makes it
unrepeatable.

292 tests, 100% branch coverage on every module.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRykabMwPgDzFHcARoqpaK
2026-08-28 13:58:44 +02:00

218 lines
7.8 KiB
Python

"""pnpm 11 refuses freshly-published packages; the gate must agree.
Reporting a repo as behind a version its package manager will not install is a
finding nobody can act on -- the pre-commit hook would fail, and the fix the
message asks for would fail too.
"""
from __future__ import annotations
from datetime import datetime, timedelta, timezone
import pytest
from dep_freshness import check, quarantine
from dep_freshness.models import Dep, Finding, Severity
from dep_freshness.tests.conftest import write
NOW = datetime(2026, 8, 28, 12, 0, tzinfo=timezone.utc)
def _stamp(hours_ago: float) -> str:
return (NOW - timedelta(hours=hours_ago)).isoformat().replace("+00:00", "Z")
PACKUMENT = {
"time": {
"created": _stamp(9000),
"modified": _stamp(1),
"16.3.0": _stamp(900),
"16.3.2": _stamp(400),
"16.3.3": _stamp(18), # inside the 24h window
}
}
@pytest.fixture
def packument(monkeypatch):
def install(payload):
monkeypatch.setattr(quarantine, "get_json", lambda *_a, **_k: payload)
return install
def test_a_release_inside_the_window_is_not_installable(packument):
packument(PACKUMENT)
assert quarantine.installable_latest("x", "16.3.3", now=NOW) == "16.3.2"
def test_a_release_outside_the_window_is_installable(packument):
packument(PACKUMENT)
assert quarantine.installable_latest("x", "16.3.2", now=NOW) == "16.3.2"
def test_versions_above_the_dist_tag_are_ignored(packument):
"""npm lets a maintenance release outrank `latest` numerically."""
payload = {"time": {**PACKUMENT["time"], "17.0.0": _stamp(500)}}
packument(payload)
assert quarantine.installable_latest("x", "16.3.3", now=NOW) == "16.3.2"
def test_the_created_and_modified_keys_are_not_versions(packument):
packument({"time": {"created": _stamp(900), "modified": _stamp(1)}})
assert quarantine.installable_latest("x", "1.0.0", now=NOW) is None
def test_an_unparseable_timestamp_is_skipped(packument):
packument({"time": {"1.0.0": "not a date", "0.9.0": _stamp(500)}})
assert quarantine.installable_latest("x", "1.0.0", now=NOW) == "0.9.0"
def test_an_unparseable_ceiling_stops_narrowing_but_the_window_still_applies(
packument,
):
packument(PACKUMENT)
# No version ceiling to apply, but 16.3.3 is still 18h old.
assert quarantine.installable_latest("x", "latest", now=NOW) == "16.3.2"
def test_a_registry_without_a_time_map_is_undeterminable(packument):
packument({"versions": {"1.0.0": {}}})
assert quarantine.installable_latest("x", "1.0.0", now=NOW) is None
def test_a_missing_package_is_undeterminable(packument):
packument(None)
assert quarantine.installable_latest("x", "1.0.0", now=NOW) is None
def test_offline_is_undeterminable(monkeypatch):
from dep_freshness.registries.http import Offline
def down(*_a, **_k):
raise Offline("no network")
monkeypatch.setattr(quarantine, "get_json", down)
assert quarantine.installable_latest("x", "1.0.0") is None
def test_the_cutoff_defaults_to_now():
assert quarantine.cutoff() < datetime.now(timezone.utc)
def _dep(ecosystem="npm", pinned="16.3.2", constraint="16.3.2") -> Dep:
from pathlib import Path
return Dep(ecosystem=ecosystem, name="@testing-library/react",
constraint=constraint, path=Path("package.json"), line=1,
pinned=pinned)
def test_a_finding_only_caused_by_a_quarantined_release_is_dropped(monkeypatch):
monkeypatch.setattr(check, "installable_latest",
lambda _n, _c: "16.3.2")
finding = Finding(_dep(), Severity.STALE, "16.3.3")
assert check._unquarantine(finding) is None
def test_a_finding_that_survives_the_narrowing_is_kept(monkeypatch):
monkeypatch.setattr(check, "installable_latest", lambda _n, _c: "16.3.2")
finding = Finding(_dep(pinned="16.1.0"), Severity.STALE, "16.3.3")
survivor = check._unquarantine(finding)
assert survivor is not None
assert survivor.latest == "16.3.2"
def test_non_npm_findings_are_never_narrowed(monkeypatch):
monkeypatch.setattr(check, "installable_latest", _explode)
finding = Finding(_dep(ecosystem="pub"), Severity.STALE, "1.0.0")
assert check._unquarantine(finding) is finding
def test_a_finding_with_no_latest_is_never_narrowed(monkeypatch):
monkeypatch.setattr(check, "installable_latest", _explode)
finding = Finding(_dep(), Severity.UNKNOWN, None)
assert check._unquarantine(finding) is finding
def test_an_undeterminable_narrowing_leaves_the_finding_alone(monkeypatch):
monkeypatch.setattr(check, "installable_latest", lambda _n, _c: None)
finding = Finding(_dep(pinned="16.1.0"), Severity.STALE, "16.3.3")
assert check._unquarantine(finding) is finding
def test_a_clean_run_never_pays_for_the_full_document(repo, monkeypatch,
cache_dir):
"""The full packument is 7MB for react; it must not be fetched when
everything is already current."""
monkeypatch.setattr(check, "installable_latest", _explode)
monkeypatch.setattr("dep_freshness.resolve._fetch",
lambda _e, _n: "19.2.8")
write(repo, "package.json", '{"dependencies": {"react": "19.2.8"}}')
monkeypatch.chdir(repo)
assert check.main(["--all"]) == 0
def _explode(*_args):
raise AssertionError("the full packument must not be fetched here")
def test_a_repo_pinned_to_the_newest_installable_version_passes(
repo, monkeypatch, cache_dir
):
"""End to end: the only finding is a release pnpm would refuse, so the
gate must exit 0 rather than demand a version that cannot be installed."""
monkeypatch.setattr("dep_freshness.resolve._fetch", lambda _e, _n: "16.3.3")
monkeypatch.setattr(check, "installable_latest", lambda _n, _c: "16.3.2")
write(repo, "package.json",
'{"dependencies": {"@testing-library/react": "16.3.2"}}')
monkeypatch.chdir(repo)
assert check.main(["--all"]) == 0
def test_the_answer_is_cached_so_a_second_run_makes_no_request(packument,
cache_dir):
"""A 7MB packument per npm finding, per run, inside a pre-commit hook is
exactly what the 6h cache exists to prevent."""
from dep_freshness.cache import Cache
store = Cache(cache_dir / "registry.json")
packument(PACKUMENT)
assert quarantine.installable_latest("x", "16.3.3", now=NOW,
cache=store) == "16.3.2"
packument(None) # any further fetch would now answer "no such package"
assert quarantine.installable_latest("x", "16.3.3", now=NOW,
cache=store) == "16.3.2"
def test_a_different_dist_tag_is_a_different_cache_entry(packument, cache_dir):
"""The ceiling is part of the key: clamping a cached answer to it would
return the ceiling, which is often the release being excluded."""
from dep_freshness.cache import Cache
store = Cache(cache_dir / "registry.json")
packument(PACKUMENT)
assert quarantine.installable_latest("x", "16.3.2", now=NOW,
cache=store) == "16.3.2"
assert store.get(quarantine.CACHE_ECOSYSTEM, "x@16.3.3") is None
def test_a_stale_cache_entry_is_served_when_the_registry_is_down(packument,
cache_dir):
from dep_freshness.cache import Cache
from dep_freshness.registries.http import Offline
store = Cache(cache_dir / "registry.json")
store.put(quarantine.CACHE_ECOSYSTEM, "x@16.3.3", "16.3.2")
store._data[f"{quarantine.CACHE_ECOSYSTEM}/x@16.3.3"]["fetched_at"] = 0.0
def down(*_a, **_k):
raise Offline("no network")
monkey = down
import dep_freshness.quarantine as q
original, q.get_json = q.get_json, monkey
try:
assert q.installable_latest("x", "16.3.3", cache=store) == "16.3.2"
finally:
q.get_json = original