Files
wehub-resource-sync 2860fb5d18
Security / Dependency review (push) Has been skipped
Scorecard / Scorecard analysis (push) Failing after 0s
Validate / eval (push) Failing after 0s
Security / Dependency audit (push) Failing after 1s
Security / Secret scan (push) Failing after 1s
Validate / tests (push) Failing after 0s
Validate / mcp-tests (push) Failing after 1s
GitHub Actions Security Analysis with zizmor 🌈 / zizmor (push) Failing after 1s
Security / SAST scan (push) Failing after 13m52s
chore: import upstream snapshot with attribution
2026-07-13 12:05:33 +08:00

348 lines
15 KiB
Python

"""Tests for the fix-prescription registry (doctor plan U3, KTD 7).
One registry maps (source, failure mode) to its remediation in BOTH
natural-language and direct-CLI forms. Consumers: the doctor command (U4)
and lib/quality_nudge.py, which builds its fix text from the same entries
so the two surfaces cannot drift.
"""
import re
from pathlib import Path
from unittest.mock import patch
import pytest
from lib import health, prescriptions
REPO_ROOT = Path(__file__).resolve().parent.parent
CONFIGURATION_MD = REPO_ROOT / "CONFIGURATION.md"
# A CLI fix must start with a runnable token: the engine invocation, an env
# assignment (optionally exported), or a documented binary name.
RUNNABLE = re.compile(
r"^(?:python3 \S*last30days\.py\b"
r"|[A-Z][A-Z0-9_]*="
r"|export [A-Z][A-Z0-9_]*="
r"|(?:brew|pipx|pip|scoop|npx|npm|xurl|yt-dlp|docker) )"
)
# The seed failure inventory from the plan (U3 approach section).
SEED_INVENTORY = {
("x", "cookies_missing"),
("x", "cookies_expired"),
("scrapecreators", "key_missing"),
("bluesky", "app_password_missing"),
("youtube", "transcription_key_missing"),
("digg", "pp_cli_missing"),
("digg", "pp_cli_off_path"),
("digg", "pp_cli_broken"),
("youtube", "ytdlp_missing"),
("youtube", "ytdlp_stale"),
("youtube", "ytdlp_broken"),
("truthsocial", "token_missing"),
("xiaohongshu", "service_unreachable"),
}
def _configuration_md_slugs():
"""GitHub-style anchor slugs for every CONFIGURATION.md heading."""
slugs = set()
for line in CONFIGURATION_MD.read_text(encoding="utf-8").splitlines():
m = re.match(r"#{1,6}\s+(.*)", line)
if not m:
continue
text = re.sub(r"[^\w\s-]", "", m.group(1).lower()).strip()
slugs.add(text.replace(" ", "-"))
return slugs
# ---------------------------------------------------------------------------
# Scenario 1: completeness lint over every registered entry
# ---------------------------------------------------------------------------
class TestCompletenessLint:
def test_seed_inventory_is_registered(self):
assert SEED_INVENTORY <= set(prescriptions.REGISTRY)
def test_every_entry_has_cause_and_both_fix_forms(self):
for key, entry in prescriptions.REGISTRY.items():
assert entry.cause.strip(), f"{key}: empty cause"
assert entry.fix_nl.strip(), f"{key}: empty natural-language fix"
assert entry.fix_cli.strip(), f"{key}: empty CLI fix"
def test_every_cli_form_starts_with_a_runnable_token(self):
for key, entry in prescriptions.REGISTRY.items():
for cli in (entry.fix_cli, *entry.alt_cli):
assert RUNNABLE.match(cli), f"{key}: not runnable: {cli!r}"
def test_nl_fix_never_duplicates_the_cli_string_verbatim(self):
for key, entry in prescriptions.REGISTRY.items():
assert entry.fix_nl.strip() != entry.fix_cli.strip(), key
def test_registry_keys_match_entry_fields(self):
for (source, failure), entry in prescriptions.REGISTRY.items():
assert entry.source == source
assert entry.failure == failure
def test_anchors_point_at_real_configuration_md_headings(self):
slugs = _configuration_md_slugs()
for key, entry in prescriptions.REGISTRY.items():
if entry.anchor:
assert entry.anchor in slugs, (
f"{key}: anchor #{entry.anchor} not a CONFIGURATION.md heading"
)
def test_no_secret_looking_values(self):
"""Placeholders only - no copy-pasteable live credentials."""
secretish = re.compile(r"(sk-[A-Za-z0-9]{16,}|gsk_[A-Za-z0-9]{16,}|xox[bap]-)")
for key, entry in prescriptions.REGISTRY.items():
blob = " ".join((entry.cause, entry.fix_nl, entry.fix_cli, *entry.alt_cli))
assert not secretish.search(blob), key
# ---------------------------------------------------------------------------
# Documented CLI forms for the flagship entries
# ---------------------------------------------------------------------------
class TestDocumentedCliForms:
def test_x_cookie_fixes_use_setup_with_browser_cookie_consent(self):
expected = "python3 skills/last30days/scripts/last30days.py setup --allow-browser-cookies"
assert prescriptions.get("x", "cookies_missing").fix_cli == expected
assert prescriptions.get("x", "cookies_expired").fix_cli == expected
def test_scrapecreators_fix_is_the_github_device_flow(self):
entry = prescriptions.get("scrapecreators", "key_missing")
assert entry.fix_cli == "python3 skills/last30days/scripts/last30days.py setup --github"
def test_ytdlp_install_and_reinstall_reference_u1_health_strings(self):
"""Binary-class fixes reference U1's tables instead of restating them."""
install, reinstall = health._MANAGER_PRESCRIPTIONS["yt-dlp"]["brew"]
assert prescriptions.get("youtube", "ytdlp_missing").fix_cli == install
assert prescriptions.get("youtube", "ytdlp_broken").fix_cli == reinstall
def test_digg_install_references_u1_printing_press_command(self):
entry = prescriptions.get("digg", "pp_cli_missing")
assert entry.fix_cli == health._pp_install_cmd("digg-pp-cli")
# ---------------------------------------------------------------------------
# Scenario 2: quality_nudge text derives from the same registry entries
# ---------------------------------------------------------------------------
def _nudge(config_overrides=None, result_overrides=None, ytdlp_installed=False):
from lib.quality_nudge import compute_quality_score
from lib import youtube_yt
config = {
"AUTH_TOKEN": None,
"CT0": None,
"XAI_API_KEY": None,
"XQUIK_API_KEY": None,
"SCRAPECREATORS_API_KEY": None,
}
config.update(config_overrides or {})
results = {"x_error": None, "youtube_error": None, "reddit_error": None}
results.update(result_overrides or {})
with patch.object(youtube_yt, "is_ytdlp_installed", return_value=ytdlp_installed):
return compute_quality_score(config, results)
class TestSharedWithQualityNudge:
def test_x_cookie_expired_nudge_is_built_from_the_registry_entry(self):
entry = prescriptions.get("x", "cookies_expired")
q = _nudge(
config_overrides={"AUTH_TOKEN": "tok123"},
result_overrides={"x_error": "401 unauthorized"},
ytdlp_installed=True,
)
assert q["nudge_text"] is not None
assert entry.fix_nl in q["nudge_text"]
def test_x_cookie_missing_nudge_is_built_from_the_registry_entry(self):
entry = prescriptions.get("x", "cookies_missing")
q = _nudge(ytdlp_installed=True)
assert entry.fix_nl in q["nudge_text"]
def test_ytdlp_missing_nudge_uses_registry_cli(self):
entry = prescriptions.get("youtube", "ytdlp_missing")
q = _nudge(config_overrides={"AUTH_TOKEN": "tok123"}, ytdlp_installed=False)
assert entry.fix_cli in q["nudge_text"]
def test_ytdlp_stale_degraded_nudge_uses_registry_cli_forms(self):
entry = prescriptions.get("youtube", "ytdlp_stale")
q = _nudge(
config_overrides={"AUTH_TOKEN": "tok123"},
ytdlp_installed=True,
result_overrides={
"youtube_videos_count": 6,
"youtube_transcripts_count": 0,
},
)
assert entry.fix_cli in q["nudge_text"]
for alt in entry.alt_cli:
assert alt in q["nudge_text"]
def test_quality_nudge_source_no_longer_hardcodes_fix_strings(self):
"""The migrated fix strings must live in the registry only.
Trigger logic legitimately still reads credential names (e.g.
``config.get("XAI_API_KEY")``); this guards the FIX text.
"""
source = (
REPO_ROOT / "skills/last30days/scripts/lib/quality_nudge.py"
).read_text(encoding="utf-8")
assert "brew " not in source
assert "api.x.ai" not in source
assert "log into x.com" not in source
assert "yt-dlp: brew" not in source
# ---------------------------------------------------------------------------
# Scenario 3: unregistered failure -> generic fallback, no crash
# ---------------------------------------------------------------------------
class TestFallback:
def test_lookup_returns_none_for_unregistered(self):
assert prescriptions.lookup("linkedin", "flux_capacitor_missing") is None
def test_get_returns_generic_configuration_md_pointer(self):
entry = prescriptions.get("linkedin", "flux_capacitor_missing")
assert "CONFIGURATION.md" in entry.fix_nl
assert RUNNABLE.match(entry.fix_cli)
assert entry.source == "linkedin"
assert entry.failure == "flux_capacitor_missing"
def test_get_returns_registered_entry_when_present(self):
assert prescriptions.get("x", "cookies_missing") is prescriptions.REGISTRY[
("x", "cookies_missing")
]
# ---------------------------------------------------------------------------
# Composition with U1 dependency probes (health.DependencyProbe)
# ---------------------------------------------------------------------------
class TestDependencyProbeComposition:
def test_ok_probe_needs_no_prescription(self):
probe = health.DependencyProbe(name="yt-dlp", status=health.OK, detail="2026.06.01")
assert prescriptions.for_dependency_probe(probe) is None
def test_probe_prescription_wins_the_cli_form(self):
"""U1's machine-aware string (pipx owner here) overrides the static CLI."""
probe = health.DependencyProbe(
name="yt-dlp",
status=health.BROKEN,
detail="yt-dlp resolves to /x/yt-dlp but won't execute: stale shim",
prescription="pipx reinstall yt-dlp",
)
entry = prescriptions.for_dependency_probe(probe)
assert entry is not None
assert entry.fix_cli == "pipx reinstall yt-dlp"
# Registry vocabulary (NL form) is retained.
assert entry.fix_nl == prescriptions.get("youtube", "ytdlp_broken").fix_nl
def test_digg_off_path_probe_maps_to_the_path_entry(self):
probe = health.DependencyProbe(
name="digg-pp-cli",
status=health.MISSING,
detail=(
"digg-pp-cli is installed at /home/u/.local/bin/digg-pp-cli but "
"that directory is not on this process's PATH"
),
prescription='add $HOME/.local/bin to PATH (e.g. export PATH="$HOME/.local/bin:$PATH") so digg-pp-cli resolves',
off_path=True,
)
entry = prescriptions.for_dependency_probe(probe)
assert entry is not None
assert entry.failure == "pp_cli_off_path"
def test_digg_broken_probe_maps_to_the_reinstall_entry(self):
"""An installed-but-broken digg binary must get reinstall-framed
text, never the never-installed "install it" entry (F6); the
probe's own prescription wins the CLI form, mirroring
test_probe_prescription_wins_the_cli_form."""
reinstall = f"re-run the Printing Press install: {health.pp_install_cmd('digg')}"
probe = health.DependencyProbe(
name="digg-pp-cli",
status=health.BROKEN,
detail=(
"digg-pp-cli resolves to /home/u/.local/bin/digg-pp-cli "
"but won't execute"
),
prescription=reinstall,
)
entry = prescriptions.for_dependency_probe(probe)
assert entry is not None
assert entry.failure == "pp_cli_broken"
assert entry.fix_cli == reinstall
# Registry vocabulary (NL form) is retained and reinstall-framed.
assert entry.fix_nl == prescriptions.get("digg", "pp_cli_broken").fix_nl
assert "reinstall" in entry.fix_nl
assert entry.fix_nl != prescriptions.get("digg", "pp_cli_missing").fix_nl
def test_digg_timeout_probe_also_maps_to_the_reinstall_entry(self):
probe = health.DependencyProbe(
name="digg-pp-cli",
status=health.TIMEOUT,
detail="digg-pp-cli --version timed out",
prescription="reinstall digg-pp-cli",
)
entry = prescriptions.for_dependency_probe(probe)
assert entry is not None
assert entry.failure == "pp_cli_broken"
def test_unregistered_dependency_wraps_the_probe(self):
probe = health.DependencyProbe(
name="ffmpeg",
status=health.MISSING,
detail="ffmpeg not found on PATH",
prescription="brew install ffmpeg",
)
entry = prescriptions.for_dependency_probe(probe)
assert entry is not None
assert entry.fix_cli == "brew install ffmpeg"
assert entry.fix_nl # still has a natural-language form
# ---------------------------------------------------------------------------
# Composition with U2 backend findings (lib/backends.py)
# ---------------------------------------------------------------------------
class TestBackendComposition:
def test_bird_cookie_prescription_embeds_the_registry_cli(self):
from lib import backends, bird_x
entry = prescriptions.get("x", "cookies_missing")
ok_node = health.DependencyProbe(name="node", status=health.OK, detail="v22.0.0")
with patch.object(bird_x, "is_bird_installed", return_value=True), \
patch.object(health, "probe_dependency", return_value=ok_node):
finding = backends._X_PROBES["bird"]({})
assert finding.status == health.MISSING
assert entry.fix_cli in finding.prescription
def test_scrapecreators_prescription_embeds_the_registry_cli(self):
from lib import backends
entry = prescriptions.get("scrapecreators", "key_missing")
finding = backends._SC_SPEC.probe({})
assert finding.status == health.MISSING
assert entry.fix_cli in finding.prescription
# test_backend_descriptors requires the key name to stay present.
assert "SCRAPECREATORS_API_KEY" in finding.prescription
class TestAltCliArityPin:
"""Greptile PR review: quality_nudge composes YouTube nudges from the two
platform alternates on the ytdlp entries. The consumer is now tolerant of
any arity (degrades wording instead of crashing), and this pin keeps the
wording rich: both entries must keep at least the scoop + pip alternates."""
@pytest.mark.parametrize("failure", ["ytdlp_missing", "ytdlp_stale"])
def test_ytdlp_entries_keep_two_platform_alternates(self, failure):
entry = prescriptions.get("youtube", failure)
assert len(entry.alt_cli) >= 2, (
f"youtube/{failure} lost a platform alternate; quality_nudge "
"wording degrades (tolerant, but fix the entry or the prose)"
)