$npx -y skills add gadievron/raptor --skill github-archiveInvestigate GitHub security incidents using tamper-proof GitHub Archive data via BigQuery. Use when verifying repository activity claims, recovering deleted PRs/branches/tags/repos, attributing actions to actors, or reconstructing attack timelines. Provides immutable forensic evi
| 1 | # GitHub Archive |
| 2 | |
| 3 | **Purpose**: Query immutable GitHub event history via BigQuery to obtain tamper-proof forensic evidence for security investigations. |
| 4 | |
| 5 | ## When to Use This Skill |
| 6 | |
| 7 | - Investigating security incidents involving GitHub repositories |
| 8 | - Building threat actor attribution profiles |
| 9 | - Verifying claims about repository activity (media reports, incident reports) |
| 10 | - Reconstructing attack timelines with definitive timestamps |
| 11 | - Analyzing automation system compromises |
| 12 | - Detecting supply chain reconnaissance |
| 13 | - Cross-repository behavioral analysis |
| 14 | - Workflow execution verification (legitimate vs API abuse) |
| 15 | - Pattern-based anomaly detection |
| 16 | - **Recovering deleted content**: PRs, issues, branches, tags, entire repositories |
| 17 | |
| 18 | GitHub Archive analysis should be your **FIRST step** in any GitHub-related security investigation. Start with the immutable record, then enrich with additional sources. |
| 19 | |
| 20 | ## Core Principles |
| 21 | |
| 22 | **ALWAYS PREFER GitHub Archive as forensic evidence over**: |
| 23 | - Local git command outputs (`git log`, `git show`) - commits can be backdated/forged |
| 24 | - Unverified claims from articles or reports - require independent confirmation |
| 25 | - GitHub web interface screenshots - can be manipulated |
| 26 | - Single-source evidence - always cross-verify |
| 27 | |
| 28 | **GitHub Archive IS your ground truth for**: |
| 29 | - Actor attribution (who performed actions) |
| 30 | - Timeline reconstruction (when events occurred) |
| 31 | - Event verification (what actually happened) |
| 32 | - Pattern analysis (behavioral fingerprinting) |
| 33 | - Cross-repository activity tracking |
| 34 | - **Deleted content recovery** (issues, PRs, tags, commit references remain in archive) |
| 35 | - **Repository deletion forensics** (commit SHAs persist even after repo deletion and history rewrites) |
| 36 | |
| 37 | ### What Persists After Deletion |
| 38 | |
| 39 | **Deleted Issues & PRs**: |
| 40 | - Issue creation events (`IssuesEvent`) remain in archive |
| 41 | - Issue comments (`IssueCommentEvent`) remain accessible |
| 42 | - PR open/close/merge events (`PullRequestEvent`) persist |
| 43 | - **Forensic Value**: Recover deleted evidence of social engineering, reconnaissance, or coordination |
| 44 | |
| 45 | **Deleted Tags & Branches**: |
| 46 | - `CreateEvent` records for tag/branch creation persist |
| 47 | - `DeleteEvent` records document when deletion occurred |
| 48 | - **Forensic Value**: Reconstruct attack staging infrastructure (e.g., malicious payload delivery tags) |
| 49 | |
| 50 | **Deleted Repositories**: |
| 51 | - All `PushEvent` records to the repository remain queryable |
| 52 | - Commit SHAs are permanently recorded in archive |
| 53 | - Fork relationships (`ForkEvent`) survive deletion |
| 54 | - **Forensic Value**: Access commit metadata even after threat actor deletes evidence |
| 55 | |
| 56 | **Deleted User Accounts**: |
| 57 | - All activity events remain attributed to deleted username |
| 58 | - Timeline reconstruction remains possible |
| 59 | - **Limitation**: Direct code access lost, but commit SHAs can be searched elsewhere |
| 60 | |
| 61 | ## Quick Start |
| 62 | |
| 63 | **Investigate if user opened PRs in June 2025:** |
| 64 | |
| 65 | ```python |
| 66 | from google.cloud import bigquery |
| 67 | from google.oauth2 import service_account |
| 68 | |
| 69 | # Initialize client (see Setup section for credentials) |
| 70 | credentials = service_account.Credentials.from_service_account_file( |
| 71 | 'path/to/credentials.json', |
| 72 | scopes=['https://www.googleapis.com/auth/bigquery'] |
| 73 | ) |
| 74 | client = bigquery.Client(credentials=credentials, project=credentials.project_id) |
| 75 | |
| 76 | # Query for PR events |
| 77 | query = """ |
| 78 | SELECT |
| 79 | created_at, |
| 80 | repo.name, |
| 81 | JSON_EXTRACT_SCALAR(payload, '$.pull_request.number') as pr_number, |
| 82 | JSON_EXTRACT_SCALAR(payload, '$.pull_request.title') as pr_title, |
| 83 | JSON_EXTRACT_SCALAR(payload, '$.action') as action |
| 84 | FROM `githubarchive.day.202506*` |
| 85 | WHERE |
| 86 | actor.login = 'suspected-actor' |
| 87 | AND repo.name = 'target/repository' |
| 88 | AND type = 'PullRequestEvent' |
| 89 | ORDER BY created_at |
| 90 | """ |
| 91 | |
| 92 | results = client.query(query) |
| 93 | for row in results: |
| 94 | print(f"{row.created_at}: PR #{row.pr_number} - {row.action}") |
| 95 | print(f" Title: {row.pr_title}") |
| 96 | ``` |
| 97 | |
| 98 | **Expected Output (if PR exists)**: |
| 99 | ``` |
| 100 | 2025-06-15 14:23:11 UTC: PR #123 - opened |
| 101 | Title: Add new feature |
| 102 | 2025-06-20 09:45:22 UTC: PR #123 - closed |
| 103 | Title: Add new feature |
| 104 | ``` |
| 105 | |
| 106 | **Interpretation**: |
| 107 | - **No results** → Claim disproven (no PR activity found) |
| 108 | - **Results found** → Claim verified, proceed with detailed analysis |
| 109 | |
| 110 | ## Setup |
| 111 | |
| 112 | ### Prerequisites |
| 113 | |
| 114 | 1. **Google Cloud Project**: |
| 115 | - Login to [Google Developer Console](https://console.cloud.google.com/) |
| 116 | - Create a project and activate BigQuery API |
| 117 | - Create a service account with `BigQuery User` role |
| 118 | - Download JSON credentials file |
| 119 | |
| 120 | 2. **Install BigQuery Client**: |
| 121 | ```bash |
| 122 | pip install google-cloud-bi |