audit-labs/audit-tools

A collection of scripts, queries, and other goodies you can use in an audit.

clone: git clone https://gitbay.org/audit-labs/audit-tools.git

main: tui/tests/test_github_runner.py · raw

  1"""Tests for the TUI's GitHub audit orchestration.
  2
  3These stub out the network-bound collectors and verify run_audit's wiring:
  4argument dispatch, the shared collaborator cache, per-check error handling,
  5and that the CSV package (per-check files + summary) is written.
  6"""
  7
  8import csv
  9import os
 10
 11import pytest
 12
 13from tui import github_runner as r
 14
 15
 16@pytest.fixture
 17def fake_checks(monkeypatch):
 18    """Replace the real registry with stubbed collectors and record calls."""
 19    calls = {}
 20
 21    def base_fn(org, cfg):
 22        calls["base"] = (org, cfg)
 23        return [{"login": "alice"}, {"login": "bob"}]
 24
 25    def collabs_fn(org, cfg, repo_collabs):
 26        calls["collabs"] = (org, cfg, repo_collabs)
 27        return [{"repo": e["repo"]} for e in repo_collabs]
 28
 29    def branch_fn(org, cfg, branch):
 30        calls["branch"] = (org, cfg, branch)
 31        return [{"branch": branch}]
 32
 33    def boom_fn(org, cfg):
 34        raise RuntimeError("kaboom")
 35
 36    checks = [
 37        r.Check("base", "Base", base_fn, "base.csv"),
 38        r.Check("collabs", "Collabs", collabs_fn, "collabs.csv", arg="collabs"),
 39        r.Check("branch", "Branch", branch_fn, "branch.csv", arg="branch"),
 40        r.Check("boom", "Boom", boom_fn, "boom.csv"),
 41    ]
 42    monkeypatch.setattr(r, "CHECKS", checks)
 43
 44    fetch_calls = []
 45
 46    def fake_fetch(org, cfg):
 47        fetch_calls.append(org)
 48        return [{"repo": "repo1", "collaborators": []}]
 49
 50    monkeypatch.setattr(r.members, "fetch_repo_collaborators", fake_fetch)
 51
 52    return calls, fetch_calls
 53
 54
 55def run(tmp_path, keys, fake_checks, branch="main"):
 56    events = []
 57    sections = r.run_audit(
 58        org="acme",
 59        token="tok",
 60        output_dir=str(tmp_path),
 61        branch=branch,
 62        selected_keys=keys,
 63        on_event=events.append,
 64    )
 65    return events, sections
 66
 67
 68def test_argument_dispatch_and_files(tmp_path, fake_checks):
 69    calls, _ = fake_checks
 70    run(tmp_path, ["base", "collabs", "branch"], fake_checks, "dev")
 71
 72    # Each collector was called with the right signature.
 73    assert calls["base"][0] == "acme"
 74    assert calls["collabs"][2] == [{"repo": "repo1", "collaborators": []}]
 75    assert calls["branch"][2] == "dev"
 76
 77    # CSV files were written for each check, plus the summary.
 78    for name in ("base.csv", "collabs.csv", "branch.csv", "summary.txt"):
 79        assert os.path.exists(tmp_path / name), name
 80
 81    with open(tmp_path / "base.csv", newline="") as f:
 82        assert len(list(csv.DictReader(f))) == 2
 83
 84
 85def test_collab_cache_fetched_once(tmp_path, fake_checks):
 86    _, fetch_calls = fake_checks
 87    run(tmp_path, ["collabs", "base"], fake_checks)
 88    assert fetch_calls == ["acme"]  # fetched exactly once
 89
 90
 91def test_collab_cache_skipped_when_not_needed(tmp_path, fake_checks):
 92    _, fetch_calls = fake_checks
 93    run(tmp_path, ["base"], fake_checks)
 94    assert fetch_calls == []  # no collabs check selected -> no fetch
 95
 96
 97def test_failing_check_does_not_abort_run(tmp_path, fake_checks):
 98    events, sections = run(tmp_path, ["boom", "base"], fake_checks)
 99
100    kinds = [(e.kind, e.label) for e in events]
101    assert ("error", "Boom") in kinds
102    assert ("done", "Base") in kinds  # base still ran after boom failed
103
104    labels = dict(sections)
105    assert labels["Boom"] == 0
106    assert labels["Base"] == 2
107
108
109def test_summary_event_totals_rows(tmp_path, fake_checks):
110    events, _ = run(tmp_path, ["base", "branch"], fake_checks)
111    summary = [e for e in events if e.kind == "summary"]
112    assert len(summary) == 1
113    assert summary[0].count == 3  # 2 base + 1 branch
114    assert summary[0].label == str(tmp_path)