Metadata-Version: 2.4
Name: slopgate
Version: 0.1.0
Summary: A CI gate against slopsquatting and hallucinated dependencies (Python / npm / Go).
Project-URL: Homepage, https://github.com/nullracodes/slopgate
Project-URL: Source, https://github.com/nullracodes/slopgate
Author: Nullra
License: MIT
License-File: LICENSE
Keywords: ai,appsec,ci,dependencies,security,slopsquatting,supply-chain
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Requires-Python: >=3.11
Description-Content-Type: text/markdown

# slopgate

A CI gate against **slopsquatting** and hallucinated dependencies for **Python, npm, and Go**.

LLMs hallucinate plausible package names. Attackers pre-register them. An AI coding agent then adds the dependency with no human at the install checkpoint. `slopgate` is the checkpoint: it runs in CI, looks at the dependencies a change introduces, and fails the build on the ones that carry a slopsquat signature.

It has **zero third-party runtime dependencies**. A tool that guards your
dependency surface shouldn't widen it.

```
✗ BLOCK   pypi:reqeusts          name does not exist on the registry and closely
                                 resembles 'requests' — typo/slopsquat signature
✗ BLOCK   pypi:hallucinated-pkg  name does not exist on the registry —
                                 likely a hallucinated dependency
! WARN    npm:lodahs             resembles popular package 'lodash'
✓ ok      pypi:requests          (silent unless --verbose)
```

## Why this exists, and what makes it different

Most "AI supply chain" material tells you to *write a policy* and *inventory your shadow AI*. This is the control that actually runs in the pipeline. The hard part of a tool like this isn't the plumbing — it's the **signal-to-noise discipline**. A gate that flags every new package gets disabled on the first false positive, and then you have no gate. So `slopgate` is built around one rule: **block only on the intersection of signals that actually describes the attack; warn on the rest; pass everything else silently.**

## The threat model (read this — the thresholds are yours to own)

A brand-new package is not inherently malicious. A name near a popular one is
not inherently malicious. The slopsquat *signature* is the **intersection**:

| Verdict | Signature |
|---|---|
| **BLOCK** | Name doesn't exist on the registry (hallucination or typo) |
| **BLOCK** | Freshly registered **and** resembles a popular package (the bullseye) |
| **BLOCK** | Freshly registered **and** no source repo **and** a single version (throwaway publish) |
| **WARN** | Resembles a popular package but is established (could be a known squat — needs eyes, not an auto-fail) |
| **WARN** | Recently published, on its own |
| **WARN** | Registry lookup failed — never block on a transport error |
| **OK** | Everything else, silently |

The default thresholds live in `slopgate/score.py` and are deliberately
conservative:

- `fresh_days = 14` — the window slopsquat registrations live in.
- `young_days = 90` — worth a warning, not a block.
- `immature_versions = 2` — below this, a package is "immature".

**These are starting points, not gospel.** They encode *a* risk tolerance; yours may differ. The similarity corpus in `slopgate/corpus.py` is the other knob: it's a curated set of the most-impersonated packages per ecosystem, kept small to hold the false-positive rate down. Swap in a real top-N-by-downloads list for production — bigger corpus catches more and warns more, and that trade-off is your call.

## Install

```bash
pip install slopgate
# or, from source:
pip install git+https://github.com/nullracodes/slopgate
```

## Use

```bash
slopgate scan .                       # scan every manifest under cwd
slopgate scan requirements.txt        # one file
slopgate scan . --strict              # warnings fail the build too
slopgate scan . --offline             # name-similarity only, no registry calls
slopgate scan . --ignore my-internal-pkg another-internal-pkg
slopgate scan . --format sarif --output slopgate.sarif
```

In a PR, evaluate **only the dependencies the PR adds** — the signal-to-noise
contract:

```bash
slopgate scan . --added-only --base-ref origin/main
```

Exit codes: `0` clean, `1` at least one BLOCK (or any WARN under `--strict`),
`2` usage error.

### Supported manifests

- **PyPI**: `requirements*.txt` (follows `-r`/`-c` includes, detects `--hash=`
  pins), `pyproject.toml` (PEP 621 and Poetry)
- **npm**: `package.json` (+ lockfile presence for hash-pinning detection)
- **Go**: `go.mod` (+ `go.sum` presence)

No PHP, no Java — out of scope, on purpose.

SARIF findings include the manifest line number where a manifest format exposes it (requirements, go.mod), so GitHub maps each finding to a line, not just a file.

## GitHub Actions

A ready-to-use workflow ships in `.github/workflows/slopgate.yml`. It runs on PRs that touch a manifest, evaluates only newly-added deps, uploads SARIF to the Security tab, and fails the check on a BLOCK.

## A note on building this with an AI coding agent

This tool was scaffolded with an AI coding agent; the irony is not lost on me. If you do the same, dogfood the thesis: pin every dependency the agent proposes, review the dependency diff before install, don't run package operations on auto-approve, and sandbox the agent. The most honest demo of a slopsquatting gate is catching the moment your own agent reaches for a package that doesn't exist.

## License

MIT.
