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

b7b1adecfd26b19758b9474c3e78f52a6418d0e1

verified · cmc

author: Christian Cleberg <hello@cleberg.net> · 2025-05-07T00:58:47Z

add gitlab repositories.py script
 applications/gitlab/README.org      | 20 ++++++++++++++++-
 applications/gitlab/repositories.py | 43 +++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/applications/gitlab/README.org b/applications/gitlab/README.org
index 37ce59b..2afc363 100644
--- a/applications/gitlab/README.org
+++ b/applications/gitlab/README.org
@@ -59,7 +59,7 @@ python ./branch_protections.py
 
 * =passwords.py=
 
-\*This script does not apply to GitLab.com. This is for self-hosted instances only.*\
+*This script does not apply to GitLab.com. This is for self-hosted instances only.*
 
 #+begin_src sh
 python ./passwords.py
@@ -82,6 +82,24 @@ Group: 105300140
     2025-04-08T03:33:17.055Z : Action: member_created, Member: 128029250, Author: 24608590
 #+end_src
 
+* =repositories.py=
+
+#+begin_src shell
+python ./repositories.py
+#+end_src
+
+#+begin_src text
+# User ID Example
+Projects under ID: ccleberg:
+- audit-tools (ID: 68757698)
+- cleberg.net (ID: 68701468)
+
+# Group ID Example
+Projects under ID: phryq:
+- Yoshi Cli (ID: 68757750)
+- pages-demo (ID: 68757186)
+#+end_src
+
 * =users.py=
 
 #+begin_src sh
diff --git a/applications/gitlab/repositories.py b/applications/gitlab/repositories.py
new file mode 100644
index 0000000..a955a49
--- /dev/null
+++ b/applications/gitlab/repositories.py
@@ -0,0 +1,43 @@
+"""
+List all repositories (projects) for a user or organization in GitLab.
+"""
+
+import requests
+
+BASE_URL = "https://gitlab.com/api/v4"
+PRIVATE_TOKEN = "your_access_token"
+USER_ID = "your_user_or_group_id"
+TIMEOUT = 30
+
+URL = f"{BASE_URL}/groups/{USER_ID}/projects" # Group URL
+# URL = f"{BASE_URL}/users/{USER_ID}/projects" # User URL
+HEADERS = {"PRIVATE-TOKEN": PRIVATE_TOKEN}
+
+
+def list_projects(user_or_group_id):
+    PER_PAGE = 100
+    page = 1
+    projects = []
+
+    while True:
+        response = requests.get(URL, headers=HEADERS, timeout=TIMEOUT, params={"page": page, "per_page": PER_PAGE})
+
+        if response.status_code == 200:
+            current_projects = response.json()
+            if not current_projects:
+                break
+            projects.extend(current_projects)
+            page += 1
+        else:
+            print(f"Failed to retrieve projects: {response.status_code} - {response.text}")
+            break
+
+    if projects:
+        print(f"Projects under ID: {user_or_group_id}:")
+        for project in projects:
+            print(f"- {project['name']} (ID: {project['id']})")
+    else:
+        print(f"No projects found for ID: {user_or_group_id}.")
+
+if __name__ == "__main__":
+    list_projects(USER_ID)