Metadata-Version: 2.5
Name: pinhaul
Version: 0.4.5
Summary: Runtime dependency inventory for Pinhaul: one import, your project reports what it actually runs.
Project-URL: Homepage, https://pinhaul.io
Author: Reknown
License: Proprietary
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24
Provides-Extra: dotenv
Requires-Dist: python-dotenv>=1.0; extra == 'dotenv'
Provides-Extra: scan
Requires-Dist: bandit>=1.7; extra == 'scan'
Description-Content-Type: text/markdown

# pinhaul (Python SDK + CLI)

Runtime dependency security for vibe coders: one import (or one `docker run` with the
[agent](../agent)) and Pinhaul knows exactly what your project *actually* runs, scans it,
and tells you what matters in plain language.

## Install

```bash
pip install pinhaul            # or: pip install "pinhaul[dotenv]" for .env loading
```

## Quickstart

```bash
# 1. Get an API key
pinhaul register --email you@example.com

# 2. Add the key to your project
echo 'PINHAUL_API_KEY=<your key>' >> .env

# 3. One line in your app's entrypoint
```

```python
from pinhaul import Pinhaul
Pinhaul(project_name="my-app", environment="prod", metadata={"team": "core"})
```

That's it. On startup, Pinhaul captures Python builtins (version, implementation,
platform, script name, hostname) and the package versions **actually loaded in your
process** — runtime truth, not a requirements.txt guess — and reports them to your
Pinhaul cloud in a background thread that can never crash or block your app.

## Snapshot caching (don't re-send what didn't change)

The SDK fingerprints the full payload (python facts + metadata + loaded inventory,
sorted so import order doesn't matter) and caches it under
`~/.cache/pinhaul/snapshots/`. An unchanged environment within the TTL sends
**nothing**; any change to python version, metadata, or a package version ships
immediately. After the TTL (default 6h) the next start re-sends once as a liveness
heartbeat — the server deduplicates that without creating rows.

| Env var | Default | Effect |
|---|---|---|
| `PINHAUL_REPORT_TTL` | `21600` (6h) | Seconds an unchanged fingerprint is suppressed. `0` = always send |
| `PINHAUL_NO_CACHE` | unset | Set to disable client caching entirely |

`Pinhaul(..., force=True)` bypasses the cache for one explicit send. Server-side
dedup (same fingerprint within its window) protects against cache misses, CI, and
second machines regardless of client settings. Check what happened via
`ds.last_result`: `sent` / `deduplicated` / `skipped` / `disabled`.

## What it sends (and never sends)

✅ python version/implementation, platform, script *basename*, hostname, loaded package
names+versions, the metadata you explicitly pass.

❌ environment variables, file paths, source code, secrets, anything else.

Set `PINHAUL_DISABLE=1` to no-op (e.g. in CI). Set `PINHAUL_DEBUG=1` to print
diagnostics to stderr on failure.

## Local scan engines (feature-gated)

```bash
pinhaul scan --code                     # bandit SAST over your python code
pinhaul scan --secrets                  # gitleaks over your git history (full history, redacted)
pinhaul scan --code --secrets --project my-app
```

- `--code` needs bandit: `pip install "pinhaul[scan]"`
- `--secrets` needs the [gitleaks](https://github.com/zricethezav/gitleaks) binary on your PATH
- Engines are enabled per plan server-side; a disabled engine prints 🔒 instead of running
- **Privacy:** code snippets are never sent (bandit findings carry test id + file:line only);
  gitleaks runs with `--redact` and secret values are stripped client-side *and* server-side

## CLI

```bash
pinhaul doctor [--docker]             # diagnose setup: API, key, cache, socket
pinhaul status                        # account + project health
pinhaul report [--project my-app]     # severity summary + dependency intel + AI insight
pinhaul findings [--severity critical,high] [--source trivy,osv,bandit,gitleaks,depintel]
pinhaul mute 7643 [7644 ...]          # hide accepted-risk findings from reports/alerts
pinhaul unmute 7643
pinhaul sbom --project my-app --out sbom.json   # CycloneDX 1.5 from runtime inventory
pinhaul analyze [--project my-app]    # queue an AI triage run
pinhaul init --name my-app            # print the integration snippet
```

API endpoint defaults to `http://127.0.0.1:8000` for local development; override with
`PINHAUL_API_URL` or `--api-url`.

## Development

```bash
cd sdk && python3 -m venv .venv && . .venv/bin/activate
pip install -e . && python -m unittest discover tests -v
```
