# Secret Scanning Setup

Two-layer defense against accidentally publishing secrets:

1. **Gitleaks** — pre-commit hook catches secrets before they enter version control
2. **TruffleHog** — pre-publish scan catches secrets inside built packages (`.tar.gz`, `.whl`)

## Install tools

```bash
brew install gitleaks trufflehog
uv tool install pre-commit
```

## Layer 1: Pre-commit hook (Gitleaks)

### Setup for a new repo

Add `.pre-commit-config.yaml` to the repo root:

```yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.3  # check https://github.com/gitleaks/gitleaks/releases
    hooks:
      - id: gitleaks
```

Install the hook:

```bash
# Standard git repo
pre-commit install

# Jujutsu (jj) repo
GIT_DIR=.jj/repo/store/git pre-commit install
```

Now every commit is scanned automatically. Gitleaks detects 300+ secret types
including PyPI tokens, AWS keys, GitHub tokens, private keys, etc.

### Manual scan

```bash
# Scan working directory (no git history)
gitleaks detect --source . --no-git --redact

# Scan git history
gitleaks detect --source . --redact

# Scan specific files
gitleaks detect --source src/ --no-git --redact
```

### Allow known false positives

Create `.gitleaksignore` in the repo root with the fingerprint of the finding:

```
# Example: test fixture with fake API key
a]3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b:src/tests/fixtures/fake_config.json:aws-access-key-id:3
```

Run `gitleaks detect` without `--redact` to see fingerprints.

## Layer 2: Pre-publish scan (TruffleHog)

TruffleHog scans inside archives — it unpacks `.tar.gz` and `.whl` files and
checks every file within, including `.pyc` bytecode. This catches secrets that
survive in built packages even when the source is clean (e.g. cached bytecode,
accidentally included config files).

### Manual scan

```bash
# Build packages
uv build

# Scan built packages
trufflehog filesystem dist/ --fail --no-update

# Scan with verification (checks if secrets are still active)
trufflehog filesystem dist/ --fail --only-verified --no-update
```

### Makefile target

Add to your `Makefile`:

```makefile
.PHONY: build publish scan-dist

build:
	uv build

scan-dist: build
	trufflehog filesystem dist/ --fail --no-update

publish: build scan-dist
	uv publish
```

Then `make publish` is the safe one-command workflow.

## Checklist for new repos

1. Add `.envrc`, `.env`, `*.pem`, `*.key` to `.gitignore`
2. Add those same patterns to your build tool's exclude list:
   ```toml
   # pyproject.toml (hatchling)
   [tool.hatch.build]
   exclude = [".jj/", ".envrc", ".env", "*.pem", "*.key"]
   ```
3. Add `.pre-commit-config.yaml` (see above)
4. Run `pre-commit install` (or `GIT_DIR=.jj/repo/store/git pre-commit install`)
5. Add `scan-dist` and `publish` targets to Makefile
6. Always use `make publish` instead of bare `uv publish`

## What happened

A PyPI API token in `.envrc` was included in the sdist because hatch didn't
exclude it. The token was published to PyPI inside `gaol-2026.3.1.tar.gz`.
Deps.dev (a third-party service) detected it and PyPI automatically revoked it.

The root cause was two missing safeguards:
- `.envrc` wasn't in `.gitignore` or the hatch build excludes
- No secret scanning in the build/publish pipeline

Both layers above would have independently caught this before publication.
