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