utils/dep_freshness/tests/test_check_allowlist.py
Krzysztof kuhy Rudnicki 978d32af3a Don't judge allowlist rot from a file-scoped run; cut two library versions
Two things, because the first is what blocked the second from committing.

**The rot check was scope-blind.** pre-commit passes only the staged
manifests, so a run that sees no package.json cannot learn anything about
whether the fleet-wide typescript hold is still needed -- yet it concluded the
entry was dead and exited 2. Staging two pubspec.yaml files in utils was
enough to make the repo uncommittable. The dead-entry check now runs only
under --all, which is CI and the manual whole-repo run; a subset scan has seen
a subset by construction.

**crdt_sync_dart 0.11.1 and design_system 0.2.1.** Both had dependency
upgrades land after their newest tag, so a consumer moving to "latest tag"
would pick up the pre-upgrade constraints (crdt_sync_dart-v0.11.0 still
carries `crypto: ^3.0.7`, `http: ^1.6.0`, `lints: ^5.0.0`) while carrying its
own new exact pins -- the unsatisfiable-resolution case exact pins create.
Version bump only; the dependency work is already in 922fb36 and 704c67e.

The allowlist end-to-end tests moved to their own file for the 250-line cap,
and `run`/`canned` moved to conftest so both files share one definition.
`canned` is no longer autouse: the resolver tests patch `_fetch` themselves.

293 tests, 100% branch coverage on every production module.

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

132 lines
3.9 KiB
Python

"""Allowlist behaviour, end to end: what an exception excuses, and when it rots.
Split out of test_check.py for the 250-line cap. The fixtures (`run`,
`canned`, `repo`, and the `no_shared_allowlist` redirect) live in conftest.py
so both files see one definition.
"""
from __future__ import annotations
from datetime import date, timedelta
from dep_freshness.tests.conftest import (
ALLOWLIST,
CURRENT_PUBSPEC,
STALE_PUBSPEC,
write,
)
SHARED = """\
exceptions:
- ecosystem: pub
package: some_other_package
pinned: "1.0.0"
reason: "a fleet-wide hold on something this repo does not use"
blocked_by: "transitive:whatever@1.0.0"
"""
def test_a_transitive_exception_excuses_the_finding(repo, run):
write(repo, "pubspec.yaml", STALE_PUBSPEC)
write(repo, ALLOWLIST, """\
exceptions:
- ecosystem: pub
package: http
pinned: "1.5.0"
reason: "something upstream holds it"
blocked_by: "transitive:some_pkg@1.0.0"
""")
assert run("--all") == 0
def test_an_exception_prints_loudly_even_on_success(repo, run, capsys):
test_a_transitive_exception_excuses_the_finding(repo, run)
err = capsys.readouterr().err
assert "DEPENDENCY EXCEPTION IN USE" in err
assert "still blocking" in err
def test_an_exception_with_nothing_left_to_excuse_is_an_error(repo, run, capsys):
write(repo, "pubspec.yaml", CURRENT_PUBSPEC)
write(repo, ALLOWLIST, """\
exceptions:
- ecosystem: pub
package: http
pinned: "1.5.0"
reason: "stale entry nobody removed"
blocked_by: "transitive:some_pkg@1.0.0"
""")
assert run("--all") == 2
assert "no longer stale" in capsys.readouterr().err
def test_a_file_scoped_run_never_judges_an_entry_dead(repo, run, capsys):
"""pre-commit passes staged files, so it only ever sees a subset.
The entry below excuses a dependency that lives in a manifest outside the
scoped path. `--all` would find it stale and mark the entry used; a scoped
run cannot, and must not conclude the entry is rot -- that failed a commit
in utils over the fleet-wide typescript hold when the staged files were
two pubspec.yaml.
"""
write(repo, "pubspec.yaml", STALE_PUBSPEC)
write(repo, "sub/pubspec.yaml", CURRENT_PUBSPEC)
write(repo, ALLOWLIST, """\
exceptions:
- ecosystem: pub
package: http
pinned: "1.5.0"
reason: "held by something upstream"
blocked_by: "transitive:some_pkg@1.0.0"
""")
assert run("sub/pubspec.yaml") == 0
assert "no longer stale" not in capsys.readouterr().err
# The same allowlist over the whole repo still excuses, not rots.
assert run("--all") == 0
def test_an_expired_allowlist_exits_two(repo, run, capsys):
write(repo, "pubspec.yaml", STALE_PUBSPEC)
yesterday = (date.today() - timedelta(days=1)).isoformat()
write(repo, ALLOWLIST, f"""\
exceptions:
- ecosystem: pub
package: http
pinned: "1.5.0"
reason: "held"
blocked_by: "discretionary"
expires: "{yesterday}"
""")
assert run("--all") == 2
assert "Allowlist ERROR" in capsys.readouterr().err
def test_an_inherited_entry_this_repo_does_not_need_is_not_rot(
repo, run, no_shared_allowlist
):
"""A fleet-wide hold on typescript excuses nothing in a Flutter app.
Treating that as a dead entry would make every repo without the dependency
uncommittable -- the shared allowlist would be unusable for the exact case
it exists for.
"""
no_shared_allowlist.write_text(SHARED, encoding="utf-8")
write(repo, "pubspec.yaml", CURRENT_PUBSPEC)
assert run("--all") == 0
def test_a_repo_local_entry_with_nothing_to_excuse_is_still_rot(
repo, run, no_shared_allowlist
):
no_shared_allowlist.write_text(SHARED, encoding="utf-8")
write(repo, "pubspec.yaml", CURRENT_PUBSPEC)
write(repo, ALLOWLIST, """\
exceptions:
- ecosystem: pub
package: http
pinned: "1.5.0"
reason: "this repo's own stale entry"
blocked_by: "transitive:x@1.0.0"
""")
assert run("--all") == 2