$npx -y skills add opendatahub-io/ai-helpers --skill python-packaging-git-auditInspect recent git history of a Python package repository for suspicious commits touching supply-chain-sensitive files, then triage findings with AI reasoning to produce a structured risk report section.
| 1 | # Python Packaging Git Audit |
| 2 | |
| 3 | Inspects the recent git history of a Python package repository for commits |
| 4 | that modify supply-chain-sensitive files (setup.py, CI configs, .pth files, |
| 5 | etc.) and contain suspicious patterns. Produces a self-contained "Git History |
| 6 | Analysis" report section with triaged findings and a risk assessment. |
| 7 | |
| 8 | ## Inputs |
| 9 | |
| 10 | - **repo_path** (required): Local filesystem path to a git repository |
| 11 | - **output_file** (optional): Write the report section to this file path instead of |
| 12 | returning it inline. The first line of the file must be `RISK_RATING:<value>` so |
| 13 | the orchestrator can parse it without reading the full report. |
| 14 | |
| 15 | ## Step 1: Enumerate Commits |
| 16 | |
| 17 | Determine the number of commits available and scan up to the last 50: |
| 18 | |
| 19 | ```bash |
| 20 | git -C <repo-path> log -50 --format='%H' |
| 21 | ``` |
| 22 | |
| 23 | ## Step 2: Filter Sensitive Files |
| 24 | |
| 25 | From those commits, identify ones that modify supply-chain-sensitive files: |
| 26 | |
| 27 | - `setup.py`, `setup.cfg`, `pyproject.toml`, `MANIFEST.in` |
| 28 | - `.github/workflows/*.yml`, `.gitlab-ci.yml` |
| 29 | - Any `.pth` files |
| 30 | - `__init__.py` files at package root |
| 31 | |
| 32 | ```bash |
| 33 | git -C <repo-path> log -50 --diff-filter=ACMR --name-only --format='COMMIT:%H|%aI|%ae' -- \ |
| 34 | setup.py setup.cfg pyproject.toml MANIFEST.in \ |
| 35 | '.github/workflows/*.yml' .gitlab-ci.yml \ |
| 36 | '*.pth' '*/__init__.py' |
| 37 | ``` |
| 38 | |
| 39 | ## Step 3: Search for Suspicious Patterns |
| 40 | |
| 41 | For each flagged commit, extract the diff and search for suspicious patterns: |
| 42 | |
| 43 | - **Code execution**: `eval(`, `exec(`, `compile(` |
| 44 | - **Process spawning**: `subprocess`, `os.system`, `os.popen` |
| 45 | - **Encoding/serialization**: `base64`, `marshal`, `pickle` |
| 46 | - **Network access**: `socket`, `urllib`, `requests.get`, `httpx` |
| 47 | - **Native code**: `ctypes`, `cffi` |
| 48 | - **Embedded URLs**: `http://`, `https://` |
| 49 | |
| 50 | ```bash |
| 51 | git -C "<repo-path>" show --format= -m --first-parent "<commit>" -- "<file>" | \ |
| 52 | grep -nE 'eval\(|exec\(|compile\(|subprocess|os\.system|os\.popen|base64|marshal|pickle|socket|urllib|requests\.get|httpx|ctypes|cffi|https?://' |
| 53 | ``` |
| 54 | |
| 55 | Collect per finding: commit hash, author, date, file modified, and matching patterns. |
| 56 | |
| 57 | ## Step 4: Triage |
| 58 | |
| 59 | Review git history findings with AI reasoning. There are no deterministic rules |
| 60 | for this phase — each finding requires contextual judgment. |
| 61 | |
| 62 | For each flagged commit, consider: |
| 63 | |
| 64 | - Is this a normal dependency version bump or configuration change? |
| 65 | - Does the pattern match the package's stated purpose? |
| 66 | - Is the author a known maintainer with a history of contributions? |
| 67 | - Does the change introduce new capabilities that seem out of scope? |
| 68 | |
| 69 | Flag commits that introduced suspicious patterns into sensitive files. Assign |
| 70 | a verdict to each: |
| 71 | |
| 72 | - **Likely legitimate** — change is a normal maintenance or dependency update |
| 73 | - **Suspicious** — change introduces unexpected capabilities or patterns |
| 74 | - **Critical** — change strongly indicates malicious intent (e.g., encoded payload in install hook) |
| 75 | |
| 76 | ## Output Format |
| 77 | |
| 78 | Produce the following markdown section: |
| 79 | |
| 80 | ```markdown |
| 81 | ## Git History Analysis (Last 50 Commits) |
| 82 | |
| 83 | **Commits touching sensitive files:** {N} |
| 84 | |
| 85 | | Commit | Date | Author | File | Patterns Found | |
| 86 | |--------|------|--------|------|----------------| |
| 87 | | abc1234 | 2026-03-15 | user@example.com | setup.py | subprocess, os.system | |
| 88 | |
| 89 | **AI Assessment:** {Brief narrative on whether the git history changes look normal or concerning, with reasoning} |
| 90 | ``` |
| 91 | |
| 92 | The **risk_rating** for this phase is one of: |
| 93 | |
| 94 | - **no_issues** — No sensitive files modified in recent history |
| 95 | - **low_risk** — All findings classified as "likely legitimate" |
| 96 | - **needs_review** — One or more findings classified as "suspicious" |
| 97 | - **critical** — One or more findings classified as "critical" |
| 98 | |
| 99 | If `output_file` is provided, write the file with the first line as |
| 100 | `RISK_RATING:<value>` followed by a blank line and then the markdown section |
| 101 | above. If `output_file` is not provided, return the report section inline. |
| 102 | |
| 103 | ## Error Handling |
| 104 | |
| 105 | | Scenario | Behavior | |
| 106 | |----------|----------| |
| 107 | | Path is not a git repository | Report "not a git repository", risk_rating = needs_review | |
| 108 | | Fewer than 50 commits available | Scan all available commits, note count in report | |
| 109 | | No sensitive files modified in history | Report "no sensitive files found", risk_rating = no_issues | |