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: applications/gitlab/collectors/members.py · raw

 1"""
 2Collect group and project membership with access levels.
 3
 4GitLab access levels:
 5    0  No access     5  Minimal     10 Guest      15 Planner
 6    20 Reporter      30 Developer   40 Maintainer 50 Owner     60 Admin
 7"""
 8
 9import sys
10
11import requests
12
13from .api import enc, paginate
14
15ACCESS_LEVELS = {
16    0: "No access",
17    5: "Minimal",
18    10: "Guest",
19    15: "Planner",
20    20: "Reporter",
21    30: "Developer",
22    40: "Maintainer",
23    50: "Owner",
24    60: "Admin",
25}
26
27
28def _role(level):
29    return ACCESS_LEVELS.get(level, str(level))
30
31
32def group_members(group, cfg):
33    """Group members, including those inherited from parent groups."""
34    members = paginate(f"{cfg['base_url']}/groups/{enc(group)}/members/all", cfg)
35    return [
36        {
37            "username": m["username"],
38            "name": m.get("name", ""),
39            "access_level": m["access_level"],
40            "role": _role(m["access_level"]),
41            "state": m.get("state", ""),
42        }
43        for m in members
44    ]
45
46
47def project_members(_group, cfg, projects):
48    """Direct and inherited members of every project in the group."""
49    rows = []
50    for p in projects:
51        try:
52            members = paginate(f"{cfg['base_url']}/projects/{p['id']}/members/all", cfg)
53        except requests.HTTPError as e:
54            if e.response is not None and e.response.status_code in (403, 404):
55                print(
56                    f"  Skipping {p.get('path_with_namespace', p['id'])}: "
57                    f"members returned {e.response.status_code}",
58                    file=sys.stderr,
59                )
60                continue
61            raise
62        for m in members:
63            rows.append(
64                {
65                    "project": p.get("path_with_namespace", ""),
66                    "username": m["username"],
67                    "name": m.get("name", ""),
68                    "access_level": m["access_level"],
69                    "role": _role(m["access_level"]),
70                }
71            )
72    return rows