Skip to content

Commit 1d34223

Browse files
committed
feat: refactor into package, add tests
1 parent f05ff49 commit 1d34223

19 files changed

Lines changed: 1369 additions & 866 deletions

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
strategy:
11+
fail-fast: false
12+
matrix:
13+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
14+
15+
steps:
16+
- name: Check out repository
17+
uses: actions/checkout@v4
18+
19+
- name: Set up Python
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
24+
- name: Install package
25+
run: python -m pip install -e .
26+
27+
- name: Verify module compiles
28+
run: python -m py_compile cull.py
29+
30+
- name: Run unit tests
31+
run: python -m unittest discover -s tests -v

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
11
__pycache__/
2+
*.py[cod]
3+
*.egg-info/
4+
.coverage
5+
.venv/
6+
venv/
7+
build/
8+
dist/

README.md

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
11
# cull
22

3-
Find compromised npm packages across your infrastructure.
3+
Find compromised npm packages across your infrastructure. Only Python stdlib, no dependencies.
4+
5+
## Install
46

57
```bash
6-
python3 cull.py axios@1.14.1 axios@0.30.4 plain-crypto-js
8+
git clone https://github.com/HacktronAI/cull.git
9+
cd cull
10+
python3 -m pip install .
711
```
812

9-
Checks lock files (`pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, `bun.lock`), `node_modules`, GitHub code search, and Docker image layers (legacy + OCI). Version-aware — distinguishes compromised versions from safe pins. Exit code `1` if found, `0` otherwise.
13+
We deliberately do not publish to PyPI to avoid creating another supply-chain distribution point for a security tool. Install from a reviewed git clone instead.
14+
15+
## Usage
16+
17+
```bash
18+
cull axios@1.14.1 axios@0.30.4 plain-crypto-js
19+
```
20+
21+
Checks lock files (`pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, `bun.lock`), `node_modules`, GitHub code search, and Docker image layers (legacy + OCI). Version-aware — distinguishes compromised versions from safe pins. Exit code `0` when clean, `1` when a compromised package is found, and `2` when the scan could not complete reliably.
1022

1123
## Scan targets
1224

1325
### Local directories
1426

1527
```bash
16-
python3 cull.py axios@1.14.1 --dirs ~/projects/app1 ~/projects/app2
28+
cull axios@1.14.1 --dirs ~/projects/app1 ~/projects/app2
1729
```
1830

1931
Default: current directory.
@@ -22,7 +34,7 @@ Default: current directory.
2234

2335
```bash
2436
export GITHUB_TOKEN=ghp_...
25-
python3 cull.py axios@1.14.1 --github-org myorg
37+
cull axios@1.14.1 --github-org myorg
2638
```
2739

2840
Searches lock files via [code search API](https://docs.github.com/en/rest/search/search#search-code). Token can also be passed via `--github-token`.
@@ -32,28 +44,30 @@ Searches lock files via [code search API](https://docs.github.com/en/rest/search
3244
### Docker images
3345

3446
```bash
35-
python3 cull.py axios@1.14.1 --docker # all local images
36-
python3 cull.py axios@1.14.1 --images app:latest # specific images
47+
cull axios@1.14.1 --docker # all local images
48+
cull axios@1.14.1 --images app:latest # specific images
3749
```
3850

3951
Requires `docker` CLI. Remote images are auto-pulled; use `--no-pull` to skip.
4052

4153
### Google Cloud
4254

4355
```bash
44-
python3 cull.py axios@1.14.1 --gar-repo us-central1-docker.pkg.dev/proj/repo # Artifact Registry
45-
python3 cull.py axios@1.14.1 --gcr-project my-project # Container Registry (legacy)
56+
cull axios@1.14.1 --gar-repo us-central1-docker.pkg.dev/proj/repo # Artifact Registry
57+
cull axios@1.14.1 --gcr-project my-project # Container Registry (legacy)
4658
```
4759

4860
Requires `gcloud` CLI with `gcloud auth login` and `gcloud auth configure-docker REGION-docker.pkg.dev`.
4961

5062
## Requirements
5163

52-
Python 3.9+. Optional CLIs: `docker`, `gcloud` — scanners skip gracefully if missing.
64+
Python 3.9+. Optional CLIs: `docker`, `gcloud`. If you request a scan target whose CLI is missing or whose backend calls fail, `cull` reports an error and exits non-zero instead of silently treating that target as clean.
5365

5466
## Security
5567

56-
Stdlib only — nothing to supply-chain. External CLIs invoked only when their flags are used. Images are exported via `docker save` / `docker pull` — never `docker run`.
68+
We intentionally do not publish this to PyPI. The goal is to avoid creating another supply-chain distribution point for a security tool. Install from a reviewed git clone instead.
69+
70+
Stdlib only — nothing else to supply-chain. External CLIs invoked only when their flags are used. Images are exported via `docker save` / `docker pull` — never `docker run`.
5771

5872
## Contributing
5973

0 commit comments

Comments
 (0)