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

v1.0.0: tui/tests/test_branch_protections.py · raw

  1"""Tests for branch-protection collection, covering classic + ruleset merge."""
  2
  3import types
  4
  5from applications.github.collectors import branch_protections as bp
  6
  7CFG = {"headers": {}, "timeout": 30}
  8
  9
 10def _classic_get(status, payload=None):
 11    """Fake requests.get for the classic protection endpoint."""
 12
 13    def _get(*args, **kwargs):
 14        return types.SimpleNamespace(
 15            status_code=status,
 16            raise_for_status=lambda: None,
 17            json=lambda: payload or {},
 18        )
 19
 20    return _get
 21
 22
 23def _paginate(rules):
 24    """Fake api.paginate returning one repo, one 'main' branch, and `rules`."""
 25
 26    def _p(url, cfg, params=None):
 27        if url.endswith("/orgs/acme/repos"):
 28            return [{"name": "repo1"}]
 29        if url.endswith("/repos/acme/repo1/branches"):
 30            return [{"name": "main"}]
 31        if "/rules/branches/main" in url:
 32            return rules
 33        return []
 34
 35    return _p
 36
 37
 38def _run(monkeypatch, rules, classic_status, classic_payload=None):
 39    monkeypatch.setattr(bp, "paginate", _paginate(rules))
 40    monkeypatch.setattr(
 41        bp.requests, "get", _classic_get(classic_status, classic_payload)
 42    )
 43    rows = bp.branch_protections("acme", CFG)
 44    assert len(rows) == 1
 45    return rows[0]
 46
 47
 48def test_ruleset_only_is_reported_protected(monkeypatch):
 49    rules = [
 50        {
 51            "type": "pull_request",
 52            "parameters": {
 53                "required_approving_review_count": 2,
 54                "require_code_owner_review": True,
 55                "dismiss_stale_reviews_on_push": True,
 56            },
 57        },
 58        {"type": "non_fast_forward", "parameters": {}},
 59    ]
 60    row = _run(monkeypatch, rules, classic_status=404)
 61    assert row["protected"] is True
 62    assert row["protection_source"] == "ruleset"
 63    assert row["required_reviews"] == 2
 64    assert row["require_code_owner_reviews"] is True
 65    assert row["dismiss_stale_reviews"] is True
 66
 67
 68def test_ruleset_status_checks(monkeypatch):
 69    rules = [
 70        {
 71            "type": "required_status_checks",
 72            "parameters": {
 73                "required_status_checks": [
 74                    {"context": "build"},
 75                    {"context": "lint"},
 76                ]
 77            },
 78        }
 79    ]
 80    row = _run(monkeypatch, rules, classic_status=404)
 81    assert row["required_status_checks"] == "build, lint"
 82
 83
 84def test_classic_only(monkeypatch):
 85    payload = {
 86        "required_pull_request_reviews": {"required_approving_review_count": 1},
 87        "enforce_admins": {"enabled": True},
 88    }
 89    row = _run(monkeypatch, rules=[], classic_status=200, classic_payload=payload)
 90    assert row["protected"] is True
 91    assert row["protection_source"] == "branch protection"
 92    assert row["required_reviews"] == 1
 93    assert row["enforce_admins"] is True
 94
 95
 96def test_both_sources(monkeypatch):
 97    payload = {"required_pull_request_reviews": {"required_approving_review_count": 3}}
 98    rules = [{"type": "pull_request", "parameters": {}}]
 99    row = _run(monkeypatch, rules, classic_status=200, classic_payload=payload)
100    assert row["protection_source"] == "branch protection + ruleset"
101    # Classic values win when both are present.
102    assert row["required_reviews"] == 3
103
104
105def test_no_protection(monkeypatch):
106    row = _run(monkeypatch, rules=[], classic_status=404)
107    assert row["protected"] is False
108    assert row["protection_source"] == ""
109    assert row["required_reviews"] is None