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

6ff4af5002e813e753e66ac04ba638b371655b79

verified · cmc

author: Christian Cleberg <hello@cleberg.net> · 2026-07-04T17:20:26Z

feat: add functionality to pull audit log events

Implements: https://github.com/audit-labs/audit-tools/issues/12
 applications/github/README.md                      |  13 +-
 applications/github/audit.py                       |  10 +-
 applications/github/collectors/audit_log.py        | 202 ++++++++++++++++++---
 .../audit_log.csv                                  |   9 +
 .../branch_protections.csv                         |   8 +
 .../github_audit_audit-labs_2026-07-04/commits.csv | 141 ++++++++++++++
 .../member_roster.csv                              |   2 +
 .../permission_matrix.csv                          |   6 +
 .../privileged_access.csv                          |   6 +
 .../github_audit_audit-labs_2026-07-04/summary.txt |  15 ++
 .../team_permissions.csv                           |   3 +
 11 files changed, 382 insertions(+), 33 deletions(-)

diff --git a/applications/github/README.md b/applications/github/README.md
index 0a57854..75fe202 100644
--- a/applications/github/README.md
+++ b/applications/github/README.md
@@ -1,6 +1,8 @@
 > **NOTE**: The PAT used across all scripts needs the following minimum permissions:
 > - Repository: Actions (read), Contents (read), Metadata (read), Workflows (read)
 > - Organization: Administration (read), Members (read)
+> - Audit log collection also requires GitHub Enterprise Cloud. Classic PATs need
+>   `read:audit_log`; fine-grained tokens need Organization Administration (read).
 
 ---
 
@@ -27,9 +29,6 @@ python audit.py --org my-org --out ./output
 
 # Collect commits from a non-default branch
 python audit.py --branch develop
-
-# Include audit log (requires GitHub Enterprise)
-python audit.py --include-audit-log
 ```
 
 ## Output
@@ -47,7 +46,11 @@ Creates a directory: `<out>/github_audit_<org>_<YYYY-MM-DD>/`
 | `permission_matrix.csv` | Full user/repo/permission cross-reference |
 | `branch_protections.csv` | Branch protection settings across all repos |
 | `commits.csv` | Commit history across all repos for the target branch |
-| `audit_log.csv` | Org-level audit events (Enterprise only, opt-in) |
+| `audit_log.csv` | Branch protection and repository ruleset audit-log changes from the last 180 days (Enterprise Cloud only) |
 | `summary.txt` | Row counts per section |
 
-
+`audit_log.csv` is collected by default. GitHub only returns audit-log events
+from the past three months unless the query includes a date filter, so this
+tool filters with `created:>=<180-days-ago>` to cover GitHub's 180-day audit-log
+retention window for non-Git events. If the organization or token cannot access
+the audit log, the tool prints a warning and continues with the other evidence.
diff --git a/applications/github/audit.py b/applications/github/audit.py
index 5f6d87e..319ba86 100644
--- a/applications/github/audit.py
+++ b/applications/github/audit.py
@@ -11,7 +11,7 @@ Usage:
     python audit.py
     python audit.py --org my-org
     python audit.py --org my-org --out ./output
-    python audit.py --org my-org --branch main --include-audit-log
+    python audit.py --org my-org --branch main
 
 Output:
     <out>/github_audit_<org>_<date>/
@@ -24,7 +24,7 @@ Output:
         permission_matrix.csv
         branch_protections.csv
         commits.csv
-        audit_log.csv           (only with --include-audit-log)
+        audit_log.csv
         summary.txt
 """
 
@@ -59,7 +59,7 @@ def parse_args():
     parser.add_argument(
         "--include-audit-log",
         action="store_true",
-        help="Include audit log collection (requires GitHub Enterprise).",
+        help=argparse.SUPPRESS,
     )
     return parser.parse_args()
 
@@ -107,9 +107,7 @@ def run():
     collect("Permission matrix",      members.permission_matrix,     "permission_matrix.csv",      org, cfg, repo_collabs)
     collect("Branch protections",     branch_protections.branch_protections, "branch_protections.csv", org, cfg)
     collect("Commits",                commits.commits,               "commits.csv",                org, cfg, args.branch)
-
-    if args.include_audit_log:
-        collect("Audit log",          audit_log.audit_log,           "audit_log.csv",              org, cfg)
+    collect("Audit log branch/ruleset changes", audit_log.audit_log, "audit_log.csv",              org, cfg)
 
     print()
     csv_reporter.write_summary(output_dir, org, sections)
diff --git a/applications/github/collectors/audit_log.py b/applications/github/collectors/audit_log.py
index 782f89b..26ac896 100644
--- a/applications/github/collectors/audit_log.py
+++ b/applications/github/collectors/audit_log.py
@@ -1,53 +1,211 @@
 """
 Collect GitHub audit log events.
 
-Requires GitHub Enterprise. Skips gracefully with a warning if not available.
+Requires GitHub Enterprise Cloud. Skips gracefully with a warning if not
+available.
 """
 
+from datetime import date, datetime, timezone, timedelta
+import json
 import sys
 
-from .api import paginate
-
-# Default event categories relevant to a security audit
-DEFAULT_ACTIONS = [
-    "org.add_member",
-    "org.remove_member",
-    "org.update_member",
-    "protected_branch",
-    "repo.access",
-    "repo.create",
-    "repo.destroy",
-    "team.add_member",
-    "team.remove_member",
+import requests
+
+# GitHub audit logs retain non-Git events for 180 days. Supplying a created:
+# qualifier is required to get events older than the default three-month window.
+DEFAULT_LOOKBACK_DAYS = 180
+DEFAULT_ACTION_FAMILIES = ["protected_branch", "repository_ruleset"]
+DETAIL_FIELDS = [
+    "name",
+    "old_name",
+    "branch",
+    "repo",
+    "repository",
+    "operation_type",
+    "ruleset_id",
+    "ruleset_name",
+    "ruleset_old_name",
+    "ruleset_enforcement",
+    "ruleset_old_enforcement",
+    "ruleset_source_type",
+    "ruleset_bypass_actors",
+    "ruleset_bypass_actors_added",
+    "ruleset_bypass_actors_deleted",
+    "ruleset_bypass_actors_updated",
+    "ruleset_conditions",
+    "ruleset_conditions_added",
+    "ruleset_conditions_deleted",
+    "ruleset_conditions_updated",
+    "ruleset_rules",
+    "ruleset_rules_added",
+    "ruleset_rules_deleted",
+    "ruleset_rules_updated",
+    "required_status_checks_enforcement_level",
+    "strict_required_status_checks_policy",
+    "pull_request_reviews_enforcement_level",
+    "required_approving_review_count",
+    "require_code_owner_review",
+    "require_last_push_approval",
+    "admin_enforced",
+    "allow_force_pushes_enforcement_level",
+    "allow_deletions_enforcement_level",
+    "lock_branch_enforcement_level",
+    "linear_history_requirement_enforcement_level",
+    "signature_requirement_enforcement_level",
+    "merge_queue_enforcement_level",
 ]
 
 
-def audit_log(org, cfg, actions=None):
+def audit_log(org, cfg, actions=None, lookback_days=DEFAULT_LOOKBACK_DAYS):
     """
-    Return audit log events filtered by action list.
-    Returns an empty list with a warning if the org is not on GitHub Enterprise.
+    Return branch protection and repository ruleset audit events.
+
+    Returns an empty list with a warning if the org is not on GitHub Enterprise
+    Cloud or the token does not have audit-log access.
     """
-    actions = actions or DEFAULT_ACTIONS
+    action_families = actions or DEFAULT_ACTION_FAMILIES
     url = f"https://api.github.com/orgs/{org}/audit-log"
+    since = date.today() - timedelta(days=lookback_days)
 
     try:
-        events = paginate(url, cfg, {"action": ",".join(actions)})
+        events = []
+        for action_family in action_families:
+            params = {
+                "phrase": f"action:{action_family} created:>={since.isoformat()}",
+                "include": "web",
+                "order": "desc",
+                "per_page": 100,
+            }
+            events.extend(_paginate_audit_log(url, cfg, params))
     except Exception as e:
         if "403" in str(e) or "404" in str(e):
             print(
-                "Warning: audit log requires GitHub Enterprise -- skipping.",
+                "Warning: audit log requires GitHub Enterprise Cloud, organization owner access, and audit-log token permissions -- skipping.",
                 file=sys.stderr,
             )
             return []
         raise
 
     rows = []
-    for e in events:
+    for e in _dedupe_events(events):
         rows.append({
             "action": e.get("action", ""),
             "actor": e.get("actor", ""),
             "repo": e.get("repo", ""),
-            "created_at": e.get("created_at", ""),
+            "branch_or_pattern": _branch_or_pattern(e),
+            "operation_type": e.get("operation_type", ""),
+            "summary": _event_summary(e),
+            "details": _event_details(e),
+            "created_at": _format_created_at(e.get("created_at", "")),
             "org": e.get("org", ""),
         })
     return rows
+
+
+def _paginate_audit_log(url, cfg, params):
+    """Fetch all audit-log cursor pages by following GitHub's Link header."""
+    results = []
+    next_url = url
+    next_params = params
+
+    while next_url:
+        resp = requests.get(
+            next_url,
+            headers=cfg["headers"],
+            params=next_params,
+            timeout=cfg["timeout"],
+        )
+        resp.raise_for_status()
+        data = resp.json()
+        if not data:
+            break
+
+        results.extend(data)
+        next_url = resp.links.get("next", {}).get("url")
+        next_params = None
+
+    return results
+
+
+def _event_details(event):
+    """Compact the change-specific audit-log fields into one CSV column."""
+    details = {
+        field: event[field]
+        for field in DETAIL_FIELDS
+        if field in event and event[field] not in (None, "")
+    }
+    return json.dumps(details, sort_keys=True)
+
+
+def _dedupe_events(events):
+    """Return events once, sorted newest first."""
+    seen = set()
+    unique = []
+    for event in events:
+        key = (
+            event.get("@timestamp") or event.get("created_at"),
+            event.get("action"),
+            event.get("actor"),
+            event.get("repo"),
+            event.get("operation_type"),
+            event.get("ruleset_id"),
+            event.get("name") or event.get("ruleset_name"),
+        )
+        if key in seen:
+            continue
+        seen.add(key)
+        unique.append(event)
+    return sorted(unique, key=_event_sort_value, reverse=True)
+
+
+def _branch_or_pattern(event):
+    """Find the most useful target label for branch and ruleset audit events."""
+    return (
+        event.get("name")
+        or event.get("branch")
+        or event.get("ruleset_name")
+        or event.get("ruleset_old_name")
+        or ""
+    )
+
+
+def _event_summary(event):
+    """Build a short human-readable evidence summary for the CSV."""
+    action = event.get("action", "")
+    operation = event.get("operation_type", "")
+    repo = event.get("repo", "")
+    target = _branch_or_pattern(event)
+
+    if action.startswith("repository_ruleset."):
+        source_type = event.get("ruleset_source_type", "")
+        scope = f"{source_type.lower()} " if source_type else ""
+        label = f" '{target}'" if target else ""
+        location = f" for {repo}" if repo else ""
+        return f"{operation or action} {scope}ruleset{label}{location}".strip()
+
+    if action.startswith("protected_branch."):
+        label = f" '{target}'" if target else ""
+        location = f" in {repo}" if repo else ""
+        return f"{operation or action} branch protection{label}{location}".strip()
+
+    return action
+
+
+def _format_created_at(value):
+    """Normalize GitHub audit-log timestamps to ISO-8601 UTC strings."""
+    if value in (None, ""):
+        return ""
+    if isinstance(value, (int, float)):
+        timestamp = value / 1000 if value > 9999999999 else value
+        return datetime.fromtimestamp(timestamp, tz=timezone.utc).isoformat()
+    return str(value)
+
+
+def _event_sort_value(event):
+    value = event.get("@timestamp") or event.get("created_at") or 0
+    if isinstance(value, (int, float)):
+        return value
+    try:
+        return datetime.fromisoformat(str(value).replace("Z", "+00:00")).timestamp()
+    except ValueError:
+        return 0
diff --git a/output/github_audit_audit-labs_2026-07-04/audit_log.csv b/output/github_audit_audit-labs_2026-07-04/audit_log.csv
new file mode 100644
index 0000000..0b1171b
--- /dev/null
+++ b/output/github_audit_audit-labs_2026-07-04/audit_log.csv
@@ -0,0 +1,9 @@
+action,actor,repo,branch_or_pattern,operation_type,summary,details,created_at,org
+protected_branch.create,ccleberg,audit-labs/audit-tools,test,create,create branch protection 'test' in audit-labs/audit-tools,"{""admin_enforced"": false, ""allow_deletions_enforcement_level"": 0, ""allow_force_pushes_enforcement_level"": 0, ""linear_history_requirement_enforcement_level"": 0, ""lock_branch_enforcement_level"": 0, ""merge_queue_enforcement_level"": 0, ""name"": ""test"", ""operation_type"": ""create"", ""pull_request_reviews_enforcement_level"": 1, ""repo"": ""audit-labs/audit-tools"", ""require_code_owner_review"": false, ""require_last_push_approval"": false, ""required_approving_review_count"": 1, ""required_status_checks_enforcement_level"": 0, ""signature_requirement_enforcement_level"": 0, ""strict_required_status_checks_policy"": true}",2026-07-04T17:17:45.302000+00:00,audit-labs
+protected_branch.branch_allowances,ccleberg,audit-labs/audit-tools,test,modify,modify branch protection 'test' in audit-labs/audit-tools,"{""name"": ""test"", ""operation_type"": ""modify"", ""repo"": ""audit-labs/audit-tools""}",2026-07-04T17:17:45.273000+00:00,audit-labs
+repository_ruleset.destroy,ccleberg,,test,remove,remove organization ruleset 'test',"{""operation_type"": ""remove"", ""ruleset_conditions"": [{""id"": 2392297, ""parameters"": {""exclude"": [], ""include"": [""*""]}, ""target"": ""repository_name""}, {""id"": 2392298, ""parameters"": {""exclude"": [], ""include"": [""~ALL""]}, ""target"": ""ref_name""}], ""ruleset_enforcement"": ""enabled"", ""ruleset_id"": 2421887, ""ruleset_name"": ""test"", ""ruleset_rules"": [{""id"": 9132974, ""parameters"": {}, ""type"": ""deletion""}, {""id"": 9132975, ""parameters"": {}, ""type"": ""non_fast_forward""}, {""id"": 9132976, ""parameters"": {""allowed_merge_methods"": [""merge"", ""squash"", ""rebase""], ""authorized_dismissal_actors_only"": false, ""automatic_copilot_code_review_enabled"": false, ""dismiss_stale_reviews_on_push"": false, ""dismissal_restriction"": {""allowed_actors"": [], ""enabled"": false}, ""ignore_approvals_from_contributors"": false, ""require_code_owner_review"": false, ""require_last_push_approval"": false, ""required_approving_review_count"": 0, ""required_review_thread_resolution"": false}, ""type"": ""pull_request""}], ""ruleset_source_type"": ""Organization""}",2026-07-04T17:11:44.144000+00:00,audit-labs
+repository_ruleset.destroy,ccleberg,audit-labs/audit-tools,default,remove,remove repository ruleset 'default' for audit-labs/audit-tools,"{""operation_type"": ""remove"", ""repo"": ""audit-labs/audit-tools"", ""ruleset_conditions"": [{""id"": 26961816, ""parameters"": {""exclude"": [], ""include"": [""~DEFAULT_BRANCH""]}, ""target"": ""ref_name""}], ""ruleset_enforcement"": ""disabled"", ""ruleset_id"": 14285764, ""ruleset_name"": ""default"", ""ruleset_rules"": [{""id"": 91960318, ""parameters"": {}, ""type"": ""deletion""}, {""id"": 91960319, ""parameters"": {}, ""type"": ""non_fast_forward""}, {""id"": 91960320, ""parameters"": {""allowed_merge_methods"": [""merge"", ""squash"", ""rebase""], ""authorized_dismissal_actors_only"": false, ""dismiss_stale_reviews_on_push"": false, ""ignore_approvals_from_contributors"": false, ""require_code_owner_review"": true, ""require_last_push_approval"": false, ""required_approving_review_count"": 0, ""required_review_thread_resolution"": false, ""required_reviewers"": []}, ""type"": ""pull_request""}], ""ruleset_source_type"": ""Repository""}",2026-04-29T18:01:39.452000+00:00,audit-labs
+repository_ruleset.update,ccleberg,audit-labs/audit-tools,default,modify,modify repository ruleset 'default' for audit-labs/audit-tools,"{""operation_type"": ""modify"", ""repo"": ""audit-labs/audit-tools"", ""ruleset_enforcement"": ""disabled"", ""ruleset_id"": 14285764, ""ruleset_name"": ""default"", ""ruleset_old_enforcement"": ""enabled"", ""ruleset_source_type"": ""Repository""}",2026-03-24T16:21:32.806000+00:00,audit-labs
+repository_ruleset.create,ccleberg,audit-labs/tutorials,def,create,create repository ruleset 'def' for audit-labs/tutorials,"{""operation_type"": ""create"", ""repo"": ""audit-labs/tutorials"", ""ruleset_bypass_actors"": [], ""ruleset_conditions"": [{""id"": 26962644, ""parameters"": {""exclude"": [], ""include"": [""~DEFAULT_BRANCH""]}, ""target"": ""ref_name""}], ""ruleset_enforcement"": ""enabled"", ""ruleset_id"": 14286366, ""ruleset_name"": ""def"", ""ruleset_rules"": [{""id"": 91962929, ""parameters"": {}, ""type"": ""deletion""}, {""id"": 91962930, ""parameters"": {}, ""type"": ""non_fast_forward""}, {""id"": 91962931, ""parameters"": {""allowed_merge_methods"": [""merge"", ""squash"", ""rebase""], ""authorized_dismissal_actors_only"": false, ""dismiss_stale_reviews_on_push"": false, ""ignore_approvals_from_contributors"": false, ""require_code_owner_review"": true, ""require_last_push_approval"": false, ""required_approving_review_count"": 1, ""required_review_thread_resolution"": false, ""required_reviewers"": []}, ""type"": ""pull_request""}], ""ruleset_source_type"": ""Repository""}",2026-03-24T16:08:34.275000+00:00,audit-labs
+repository_ruleset.update,ccleberg,audit-labs/audit-tools,default,modify,modify repository ruleset 'default' for audit-labs/audit-tools,"{""operation_type"": ""modify"", ""repo"": ""audit-labs/audit-tools"", ""ruleset_enforcement"": ""enabled"", ""ruleset_id"": 14285764, ""ruleset_name"": ""default"", ""ruleset_rules_updated"": [{""id"": 91960320, ""old_parameters"": {""allowed_merge_methods"": [""merge"", ""squash"", ""rebase""], ""authorized_dismissal_actors_only"": false, ""dismiss_stale_reviews_on_push"": false, ""ignore_approvals_from_contributors"": false, ""require_code_owner_review"": false, ""require_last_push_approval"": false, ""required_approving_review_count"": 0, ""required_review_thread_resolution"": false, ""required_reviewers"": []}, ""parameters"": {""allowed_merge_methods"": [""merge"", ""squash"", ""rebase""], ""authorized_dismissal_actors_only"": false, ""dismiss_stale_reviews_on_push"": false, ""ignore_approvals_from_contributors"": false, ""require_code_owner_review"": true, ""require_last_push_approval"": false, ""required_approving_review_count"": 0, ""required_review_thread_resolution"": false, ""required_reviewers"": []}, ""type"": ""pull_request""}], ""ruleset_source_type"": ""Repository""}",2026-03-24T16:07:57.851000+00:00,audit-labs
+repository_ruleset.create,ccleberg,audit-labs/audit-tools,default,create,create repository ruleset 'default' for audit-labs/audit-tools,"{""operation_type"": ""create"", ""repo"": ""audit-labs/audit-tools"", ""ruleset_bypass_actors"": [], ""ruleset_conditions"": [{""id"": 26961816, ""parameters"": {""exclude"": [], ""include"": [""~DEFAULT_BRANCH""]}, ""target"": ""ref_name""}], ""ruleset_enforcement"": ""enabled"", ""ruleset_id"": 14285764, ""ruleset_name"": ""default"", ""ruleset_rules"": [{""id"": 91960318, ""parameters"": {}, ""type"": ""deletion""}, {""id"": 91960319, ""parameters"": {}, ""type"": ""non_fast_forward""}, {""id"": 91960320, ""parameters"": {""allowed_merge_methods"": [""merge"", ""squash"", ""rebase""], ""authorized_dismissal_actors_only"": false, ""dismiss_stale_reviews_on_push"": false, ""ignore_approvals_from_contributors"": false, ""require_code_owner_review"": false, ""require_last_push_approval"": false, ""required_approving_review_count"": 0, ""required_review_thread_resolution"": false, ""required_reviewers"": []}, ""type"": ""pull_request""}], ""ruleset_source_type"": ""Repository""}",2026-03-24T15:52:46.738000+00:00,audit-labs
diff --git a/output/github_audit_audit-labs_2026-07-04/branch_protections.csv b/output/github_audit_audit-labs_2026-07-04/branch_protections.csv
new file mode 100644
index 0000000..e3f97a0
--- /dev/null
+++ b/output/github_audit_audit-labs_2026-07-04/branch_protections.csv
@@ -0,0 +1,8 @@
+repo,branch,protected,required_reviews,dismiss_stale_reviews,require_code_owner_reviews,required_status_checks,enforce_admins,restrictions
+.github,main,False,,,,,,
+audit-tools,main,False,,,,,,
+internal-docs,main,False,,,,,,
+tutorials,ccleberg-patch-1,False,,,,,,
+tutorials,ccleberg-patch-2,False,,,,,,
+tutorials,main,False,,,,,,
+audit-labs.dev,main,False,,,,,,
diff --git a/output/github_audit_audit-labs_2026-07-04/commits.csv b/output/github_audit_audit-labs_2026-07-04/commits.csv
new file mode 100644
index 0000000..c759fe2
--- /dev/null
+++ b/output/github_audit_audit-labs_2026-07-04/commits.csv
@@ -0,0 +1,141 @@
+repo,branch,sha,author_name,author_email,date,message,additions,deletions
+.github,main,11af235ea544,Christian Cleberg,hello@cleberg.net,2025-12-24T23:11:45Z,Refactor README.md for improved clarity and structure,,
+.github,main,d1fb0920a308,Christian Cleberg,hello@cleberg.net,2025-12-24T23:05:23Z,Revise README with new website and tool details,,
+.github,main,ecbd05627da0,Christian Cleberg,hello@cleberg.net,2025-12-24T00:41:46Z,update readme,,
+.github,main,67cce50184af,Christian Cleberg,hello@cleberg.net,2025-12-23T21:42:39Z,Revise README content for NightWatch Labs,,
+.github,main,7f3439d65ba9,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-11-07T22:04:18Z,Delete README.md,,
+.github,main,6689e34edc86,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-11-07T22:04:09Z,Create README.md,,
+.github,main,0e588fad8a38,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-11-07T22:03:04Z,Create README.md,,
+audit-tools,main,36361bbe319e,Christian Cleberg,hello@cleberg.net,2026-05-07T23:20:10Z,Merge pull request #11 from audit-labs/dependabot/uv/urllib3-gte-2.7.0,,
+audit-tools,main,9735c53a4e2e,dependabot[bot],49699333+dependabot[bot]@users.noreply.github.com,2026-05-07T22:25:20Z,Update urllib3 requirement from >=2.6.3 to >=2.7.0,,
+audit-tools,main,14b8c1d88cff,Christian Cleberg,hello@cleberg.net,2026-04-24T05:11:33Z,Merge pull request #2 from audit-labs/dependabot/uv/werkzeug-gte-3.1.8,,
+audit-tools,main,9e406e328344,dependabot[bot],49699333+dependabot[bot]@users.noreply.github.com,2026-04-23T22:25:13Z,Update werkzeug requirement from >=3.1.5 to >=3.1.8,,
+audit-tools,main,43fe1e476bb5,Christian Cleberg,hello@cleberg.net,2026-03-24T16:21:51Z,fix CODEOWNERS formatting,,
+audit-tools,main,312c5d11edef,Christian Cleberg,hello@cleberg.net,2026-03-23T04:14:29Z,Merge dev: unified GitHub audit tool,,
+audit-tools,main,93ce98aee240,Christian Cleberg,hello@cleberg.net,2026-03-23T04:13:40Z,Add unified GitHub audit tool,,
+audit-tools,main,ac4dcf4f6d9c,Christian Cleberg,hello@cleberg.net,2026-02-22T05:56:11Z,update README,,
+audit-tools,main,bdae0a78d421,christian,hello@cleberg.net,2026-02-04T20:46:11Z,Add Werkzeug minimum version to requirements.txt,,
+audit-tools,main,6c99da187f65,christian,hello@cleberg.net,2026-02-04T20:45:27Z,Add urllib3 version requirement to requirements.txt,,
+audit-tools,main,a52fe0016703,Christian Cleberg,hello@cleberg.net,2025-12-24T01:09:46Z,move notebooks to new tutorials repo,,
+audit-tools,main,d23d78f98de4,Christian Cleberg,hello@cleberg.net,2025-12-24T00:40:34Z,update readme,,
+audit-tools,main,2713564fbe30,Christian Cleberg,hello@cleberg.net,2025-12-15T02:18:40Z,add aws s3 bucket testing,,
+audit-tools,main,2ff4dac3ece5,github-actions,41898282+github-actions[bot]@users.noreply.github.com,2025-12-15T01:45:51Z,Commit from GitHub Actions (Ruff),,
+audit-tools,main,bb1e7eeee904,Christian Cleberg,hello@cleberg.net,2025-12-15T01:45:10Z,add aws password testing,,
+audit-tools,main,4099585ca5fe,Christian Cleberg,hello@cleberg.net,2025-12-13T17:05:59Z,remove early exit condition,,
+audit-tools,main,bf179a484c1f,Christian Cleberg,hello@cleberg.net,2025-12-12T18:08:38Z,Merge pull request #1 from ccleberg/ccleberg-patch-1,,
+audit-tools,main,46f98e918c05,Christian Cleberg,hello@cleberg.net,2025-12-12T18:06:56Z,Implement root check and enhance error messages,,
+audit-tools,main,35be9d94adc9,Christian Cleberg,hello@cleberg.net,2025-12-12T17:42:19Z,remove invalid extra check,,
+audit-tools,main,6ad8f3001e3b,Christian Cleberg,hello@cleberg.net,2025-12-12T17:21:47Z,add logic for handling explicit and implicit root keys files,,
+audit-tools,main,cebaf4e251d2,Christian Cleberg,hello@cleberg.net,2025-12-12T16:51:55Z,enhance ssh_root_login.sh to check for keys if PermitRootLogin is enabled,,
+audit-tools,main,8444d7854e64,Christian Cleberg,hello@cleberg.net,2025-12-11T18:35:12Z,rename aws script,,
+audit-tools,main,cbc9aa65290c,Christian Cleberg,hello@cleberg.net,2025-12-11T18:33:23Z,rename aws script,,
+audit-tools,main,d4fe22a40e2d,Christian Cleberg,hello@cleberg.net,2025-12-11T18:24:14Z,add @ekraai2 as a codeowner,,
+audit-tools,main,73917d9d1b20,Christian Cleberg,hello@cleberg.net,2025-12-11T18:15:37Z,add aws script,,
+audit-tools,main,b5d44a0adec9,Christian Cleberg,hello@cleberg.net,2025-12-04T17:48:34Z,Update README with uv command for script execution,,
+audit-tools,main,4330955741a3,Christian Cleberg,hello@cleberg.net,2025-12-04T17:45:43Z,Update project title in README.md,,
+audit-tools,main,d23eed013a58,Christian Cleberg,hello@cleberg.net,2025-12-04T17:31:16Z,Set package-ecosystem to 'uv' in dependabot config,,
+audit-tools,main,dcee48cb9b65,Christian Cleberg,hello@cleberg.net,2025-12-03T20:40:15Z,Update repository clone URL and remove sections,,
+audit-tools,main,e7e1a5131931,github-actions,41898282+github-actions[bot]@users.noreply.github.com,2025-12-02T21:46:01Z,Commit from GitHub Actions (Ruff),,
+audit-tools,main,1dd04ac70eac,Christian Cleberg,hello@cleberg.net,2025-12-02T21:31:17Z,Enhance password policy verification in GitLab,,
+audit-tools,main,87e253080e68,Christian Cleberg,hello@cleberg.net,2025-08-02T18:06:22Z,fix: update README,,
+audit-tools,main,b598a79d270b,Christian Cleberg,hello@cleberg.net,2025-08-02T18:02:43Z,fix: convert README.org to README.md,,
+audit-tools,main,a24b16d1c04f,Christian Cleberg,hello@cleberg.net,2025-08-02T16:07:51Z,fix: update git links,,
+audit-tools,main,6226695a2072,Christian Cleberg,hello@cleberg.net,2025-05-29T16:41:39Z,feat: add stratified sampling script (#12),,
+audit-tools,main,ae0b864a92ce,Christian Cleberg,hello@cleberg.net,2025-05-28T18:02:35Z,feat: add jupyter notebooks folder (#11),,
+audit-tools,main,6f6c450e1400,Christian Cleberg,hello@cleberg.net,2025-05-28T17:59:42Z,feat: convert README to org-mode and update content (#10),,
+audit-tools,main,06b9975acbfa,Christian Cleberg,hello@cleberg.net,2025-05-07T16:43:30Z,Linux enhancements (#9),,
+audit-tools,main,9bc2176689de,Christian Cleberg,hello@cleberg.net,2025-05-07T03:00:21Z,add and update READMEs (#8),,
+audit-tools,main,f351e70fbdf7,Christian Cleberg,hello@cleberg.net,2025-05-07T02:54:18Z,add and update READMEs (#7),,
+audit-tools,main,95bf612c338d,Christian Cleberg,hello@cleberg.net,2025-05-07T02:31:46Z,reorganize db dir (#6),,
+audit-tools,main,d62f25007470,Christian Cleberg,hello@cleberg.net,2025-05-07T01:49:19Z,add gitlab pipelines.py script (#5),,
+audit-tools,main,714cb4c213f1,Christian Cleberg,hello@cleberg.net,2025-05-07T01:03:16Z,update .github files (#4),,
+audit-tools,main,428fd934b7f4,Christian Cleberg,hello@cleberg.net,2025-05-07T01:00:13Z,Merge pull request #3 from ccleberg/gitlab,,
+audit-tools,main,b7b1adecfd26,Christian Cleberg,hello@cleberg.net,2025-05-07T00:58:47Z,add gitlab repositories.py script,,
+audit-tools,main,b7e1fad59310,Christian Cleberg,hello@cleberg.net,2025-05-07T00:18:58Z,Merge pull request #1 from ccleberg/patch-1,,
+audit-tools,main,fc02637e4dcd,Christian Cleberg,hello@cleberg.net,2025-05-07T00:17:50Z,Merge branch 'main' into patch-1,,
+audit-tools,main,875aa2d0c6b9,Christian Cleberg,hello@cleberg.net,2025-05-07T00:17:28Z,Merge pull request #2 from ccleberg/ccleberg-patch-1,,
+audit-tools,main,06676e9afd4f,Christian Cleberg,hello@cleberg.net,2025-05-07T00:16:13Z,Create codeql.yml,,
+audit-tools,main,0213394cf7f5,Christian Cleberg,hello@cleberg.net,2025-05-07T00:13:30Z,rename os dir,,
+audit-tools,main,697ff3ad93cf,Christian Cleberg,hello@cleberg.net,2025-05-01T03:07:19Z,update README,,
+audit-tools,main,892e075443ba,Christian Cleberg,hello@cleberg.net,2025-05-01T03:05:31Z,remove .github,,
+audit-tools,main,c939edce62a1,Christian Cleberg,hello@cleberg.net,2025-04-25T22:47:34Z,update README (#8),,
+audit-tools,main,9e09baa523a2,Christian Cleberg,hello@cleberg.net,2025-04-25T22:44:49Z,update tests for linux (#7),,
+audit-tools,main,86db25856235,Christian Cleberg,hello@cleberg.net,2025-04-25T22:37:39Z,MySQL & Postgres Enhancements (#5),,
+audit-tools,main,7ba7b11f85dc,Christian Cleberg,hello@cleberg.net,2025-04-08T04:02:28Z,add coverage to readme (#4),,
+audit-tools,main,107aa4996e63,Christian Cleberg,hello@cleberg.net,2025-04-08T04:00:47Z,update readme (#3),,
+audit-tools,main,8b78620c2c39,Christian Cleberg,hello@cleberg.net,2025-04-08T03:52:59Z,Gitlab enhancements (#2),,
+audit-tools,main,bee22b97b652,Christian Cleberg,hello@cleberg.net,2025-04-05T18:43:01Z,migrate from pylint to ruff (#1),,
+audit-tools,main,304147278199,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2025-03-27T17:52:43Z,add FUNDING.yml,,
+audit-tools,main,2ba79066a6e1,Christian Cleberg,hello@cmc.pub,2025-03-15T03:26:23Z,add CODEOWNERS file,,
+audit-tools,main,233f20ecec2b,Christian Cleberg,hello@cmc.pub,2025-03-11T23:29:22Z,move from cleberg.net to cmc.pub,,
+audit-tools,main,486f01f3b546,Christian Cleberg,hello@cleberg.net,2025-01-19T15:43:57Z,fix README checkboxes for GitHub,,
+audit-tools,main,e34d04133e3d,Christian Cleberg,hello@cleberg.net,2025-01-16T20:22:37Z,minify png,,
+audit-tools,main,60c4938f3825,Christian Cleberg,hello@cleberg.net,2025-01-16T20:21:04Z,add HTML version of sampling tool,,
+audit-tools,main,20914ded9f2f,Christian Cleberg,hello@cleberg.net,2025-01-16T19:38:13Z,update .gitignore,,
+audit-tools,main,4a7fbd1cc889,Christian Cleberg,hello@cleberg.net,2024-12-28T18:16:48Z,pylint fixes,,
+audit-tools,main,e5458c8efe5f,Christian Cleberg,hello@cleberg.net,2024-12-28T18:15:15Z,pylint fixes,,
+audit-tools,main,eeadd683cdb6,Christian Cleberg,hello@cleberg.net,2024-12-28T18:02:33Z,add gitlab admins script,,
+audit-tools,main,2ee3e7af7b91,Christian Cleberg,hello@cleberg.net,2024-12-28T17:30:03Z,restructure directories,,
+audit-tools,main,be74e8cab3bb,Christian Cleberg,hello@cleberg.net,2024-11-07T02:17:15Z,remove pysa,,
+audit-tools,main,ea9931ee81f1,Christian Cleberg,hello@cleberg.net,2024-11-07T02:13:28Z,fix pysa,,
+audit-tools,main,9ae0caeb741b,Christian Cleberg,hello@cleberg.net,2024-11-07T02:10:43Z,fix pysa,,
+audit-tools,main,90a953fdb3fa,Christian Cleberg,hello@cleberg.net,2024-11-07T02:09:34Z,fix pysa,,
+audit-tools,main,c11f5ee5cab2,Christian Cleberg,hello@cleberg.net,2024-11-07T02:06:34Z,update pylint dependencies,,
+audit-tools,main,a862dbbe144e,Christian Cleberg,hello@cleberg.net,2024-11-07T02:04:31Z,fix pysa,,
+audit-tools,main,47de3e51b31d,Christian Cleberg,hello@cleberg.net,2024-11-07T02:02:33Z,add pysa,,
+audit-tools,main,4e175f8ae5f5,Christian Cleberg,hello@cleberg.net,2024-11-07T01:58:47Z,remove crda,,
+audit-tools,main,3dc9179df58f,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-11-07T01:56:00Z,Update crda.yml,,
+audit-tools,main,89b27b21700f,Christian Cleberg,hello@cleberg.net,2024-11-07T01:45:39Z,add requirements.txt,,
+audit-tools,main,020b7996cf8f,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-11-07T01:39:38Z,Merge pull request #1 from ccleberg/crda-patch,,
+audit-tools,main,79083cfcc616,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-11-07T01:37:06Z,Create crda.yml,,
+audit-tools,main,c1cfdeedc0e8,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-29T17:59:09Z,add README to github folder,,
+audit-tools,main,fc0018b36ddd,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-28T19:57:49Z,exclude R0801 from pylint,,
+audit-tools,main,c8db45d00041,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-28T19:50:25Z,add github branch protections script,,
+audit-tools,main,5cca16c570ea,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-28T19:16:42Z,add github audit log script,,
+audit-tools,main,c9cd2f443a8b,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-28T18:58:58Z,add github API scripts,,
+audit-tools,main,0ef8420632bc,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-25T17:09:05Z,typo,,
+audit-tools,main,34179451ec06,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-25T17:07:19Z,reformat sql db_password test,,
+audit-tools,main,b871e5a3197c,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-25T16:56:51Z,add SQL database password test,,
+audit-tools,main,50e5f6fd4c82,Christian Cleberg,hello@cleberg.net,2024-10-19T19:30:36Z,fix pylint issues,,
+audit-tools,main,d4dff7a2caa0,Christian Cleberg,hello@cleberg.net,2024-10-19T19:28:05Z,fix pylint issues,,
+audit-tools,main,bbf96c617d02,Christian Cleberg,hello@cleberg.net,2024-10-19T19:16:39Z,add plotly dashboard example,,
+audit-tools,main,933a5137e8fa,Christian Cleberg,hello@cleberg.net,2024-10-19T18:20:02Z,move items to project_management folder,,
+audit-tools,main,49f12cbbeaf3,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-19T18:17:35Z,add alteryx email reminders,,
+audit-tools,main,1e4badb4bceb,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-19T18:00:39Z,add project dashboard,,
+audit-tools,main,2f1bb3400c76,Christian Cleberg,hello@cleberg.net,2024-10-19T16:51:19Z,missed a couple pylint fixes in comments,,
+audit-tools,main,52ea45732eec,Christian Cleberg,hello@cleberg.net,2024-10-19T16:49:01Z,fix github actions version,,
+audit-tools,main,d6b72187ad3a,Christian Cleberg,hello@cleberg.net,2024-10-19T16:46:55Z,fix pylint issues,,
+audit-tools,main,3b03f7450c1a,Christian Cleberg,hello@cleberg.net,2024-10-19T16:41:42Z,explicitly import pandas,,
+audit-tools,main,7ac171a45380,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-19T16:40:03Z,Create pylint.yml,,
+audit-tools,main,a94928e85b08,Christian Cleberg,hello@cleberg.net,2024-10-19T16:32:25Z,move sample script to sampling dir,,
+audit-tools,main,40e83f1fc335,Christian Cleberg,hello@cleberg.net,2024-10-19T16:31:35Z,add database admin tools,,
+audit-tools,main,c588eff5bd05,Christian Cleberg,hello@cleberg.net,2024-10-19T16:27:18Z,add run hint to README,,
+audit-tools,main,9bf4bc59ee67,Christian Cleberg,hello@cleberg.net,2024-10-19T16:26:23Z,add sample.py,,
+audit-tools,main,e273f1a32f4d,Christian Cleberg,hello@cleberg.net,2024-10-19T16:26:08Z,initial commit,,
+audit-tools,main,de62dab9cbd2,Christian Cleberg,156287552+ccleberg@users.noreply.github.com,2024-10-19T15:47:17Z,Initial commit,,
+internal-docs,main,48f3e011e6e4,Christian Cleberg,hello@cleberg.net,2025-12-24T20:21:43Z,Revise onboarding steps for GitHub and Zero Trust access,,
+internal-docs,main,2c2b77f9c076,Christian Cleberg,hello@cleberg.net,2025-12-24T00:57:56Z,fix org names in onboarding template,,
+internal-docs,main,f62743ab3fd7,Christian Cleberg,hello@cleberg.net,2025-12-24T00:57:06Z,fix email example in onboarding template,,
+internal-docs,main,5f3fd3b2dd98,Christian Cleberg,hello@cleberg.net,2025-12-24T00:56:16Z,fix onboarding template formatting,,
+internal-docs,main,7a9852324fbf,Christian Cleberg,hello@cleberg.net,2025-12-24T00:55:21Z,update onboarding template to ask for ssh key,,
+internal-docs,main,8b7ec6cd6367,Christian Cleberg,hello@cleberg.net,2025-12-24T00:54:24Z,add onboarding.org,,
+internal-docs,main,f0ebc64df634,Christian Cleberg,hello@cleberg.net,2025-12-24T00:46:47Z,add onboarding.org,,
+internal-docs,main,d3577a042324,Christian Cleberg,hello@cleberg.net,2025-12-23T22:54:47Z,add onboarding template,,
+internal-docs,main,86fb0880517b,Christian Cleberg,hello@cleberg.net,2025-12-23T22:54:37Z,remove default readme,,
+internal-docs,main,296b304224d2,Christian Cleberg,hello@cleberg.net,2025-12-23T22:47:05Z,Initial commit,,
+tutorials,main,fa836e350724,Christian Cleberg,hello@cleberg.net,2026-02-22T00:06:51Z,add sampling notebook,,
+tutorials,main,f9f42bf61aa4,christian,hello@cleberg.net,2026-01-27T22:37:32Z,Merge pull request #1 from audit-labs/add/docs-and-ci,,
+tutorials,main,233a317c7b33,christian,hello@cleberg.net,2026-01-27T22:35:37Z,Update output path for HTML conversion of notebooks,,
+tutorials,main,3f27f26ef6c3,christian,hello@cleberg.net,2026-01-27T22:29:21Z,"Add environment, CI, CONTRIBUTING and CODEOFCONDUCT",,
+tutorials,main,54aaa07bf260,christian,hello@cleberg.net,2026-01-27T22:15:56Z,"Add README, environment files, CI workflow, CONTRIBUTING and Code of Conduct",,
+tutorials,main,89f799ea5806,Christian Cleberg,hello@cleberg.net,2026-01-15T15:52:19Z,remove extraneous notebook,,
+tutorials,main,8bd4c1ee76ac,Christian Cleberg,hello@cleberg.net,2025-12-24T03:51:44Z,add terminations notebook,,
+tutorials,main,8e4ddbe21763,Christian Cleberg,hello@cleberg.net,2025-12-24T01:14:09Z,update .gitignore,,
+tutorials,main,b8c7d246109c,Christian Cleberg,hello@cleberg.net,2025-12-24T01:14:02Z,update .gitignore,,
+tutorials,main,85b1c325c6a3,Christian Cleberg,hello@cleberg.net,2025-12-24T01:13:30Z,refresh notebooks for a fresh start,,
+tutorials,main,4264aafb046e,Christian Cleberg,hello@cleberg.net,2025-12-24T01:08:45Z,add LICENSE,,
+audit-labs.dev,main,0328de5faa52,Christian Cleberg,hello@cleberg.net,2026-02-21T23:04:24Z,update page design,,
+audit-labs.dev,main,8b4e9b808fb9,Christian Cleberg,hello@cleberg.net,2026-02-21T23:01:52Z,update page design,,
+audit-labs.dev,main,fb7332d56c34,Christian Cleberg,hello@cleberg.net,2025-12-24T22:34:52Z,Add GitHub Actions workflow for static site deployment,,
+audit-labs.dev,main,baaa2e05ea40,Christian Cleberg,hello@cleberg.net,2025-12-24T22:25:03Z,Add initial HTML structure for Audit Labs website,,
+audit-labs.dev,main,f9ec8d0a5ca0,Christian Cleberg,hello@cleberg.net,2025-12-24T22:20:50Z,Initial commit,,
diff --git a/output/github_audit_audit-labs_2026-07-04/member_roster.csv b/output/github_audit_audit-labs_2026-07-04/member_roster.csv
new file mode 100644
index 0000000..c9a931f
--- /dev/null
+++ b/output/github_audit_audit-labs_2026-07-04/member_roster.csv
@@ -0,0 +1,2 @@
+login,org_role,profile_url
+ccleberg,owner,https://github.com/ccleberg
diff --git a/output/github_audit_audit-labs_2026-07-04/permission_matrix.csv b/output/github_audit_audit-labs_2026-07-04/permission_matrix.csv
new file mode 100644
index 0000000..3fb82f9
--- /dev/null
+++ b/output/github_audit_audit-labs_2026-07-04/permission_matrix.csv
@@ -0,0 +1,6 @@
+repo,login,permission,visibility
+.github,ccleberg,admin,public
+audit-tools,ccleberg,admin,public
+internal-docs,ccleberg,admin,private
+tutorials,ccleberg,admin,public
+audit-labs.dev,ccleberg,admin,public
diff --git a/output/github_audit_audit-labs_2026-07-04/privileged_access.csv b/output/github_audit_audit-labs_2026-07-04/privileged_access.csv
new file mode 100644
index 0000000..0a2b346
--- /dev/null
+++ b/output/github_audit_audit-labs_2026-07-04/privileged_access.csv
@@ -0,0 +1,6 @@
+login,repo,permission,repo_visibility
+ccleberg,.github,admin,public
+ccleberg,audit-tools,admin,public
+ccleberg,internal-docs,admin,private
+ccleberg,tutorials,admin,public
+ccleberg,audit-labs.dev,admin,public
diff --git a/output/github_audit_audit-labs_2026-07-04/summary.txt b/output/github_audit_audit-labs_2026-07-04/summary.txt
new file mode 100644
index 0000000..aa37662
--- /dev/null
+++ b/output/github_audit_audit-labs_2026-07-04/summary.txt
@@ -0,0 +1,15 @@
+GitHub Audit Package
+Org: audit-labs
+
+Section                        Rows
+────────────────────────────────────────
+Member roster                      1
+2FA disabled                       0
+Outside collaborators              0
+Privileged access                  5
+Pending invitations                0
+Team permissions                   2
+Permission matrix                  5
+Branch protections                 7
+Commits                            140
+Audit log branch/ruleset changes   8
diff --git a/output/github_audit_audit-labs_2026-07-04/team_permissions.csv b/output/github_audit_audit-labs_2026-07-04/team_permissions.csv
new file mode 100644
index 0000000..3349aea
--- /dev/null
+++ b/output/github_audit_audit-labs_2026-07-04/team_permissions.csv
@@ -0,0 +1,3 @@
+team,repo,permission,members
+admins,audit-tools,admin,ccleberg
+developers,audit-tools,write,(none)