Security Scanning

haven has built-in secret detection to help you avoid accidentally committing credentials, private keys, or sensitive configuration files to your dotfile repo.

Running a scan

haven security-scan            # scan all tracked files
haven security-scan --entropy  # also flag high-entropy strings

Exits 0 when clean, 1 when findings are reported — suitable for CI or pre-push hooks.

What is checked

Check Examples flagged
Filename patterns .env, id_rsa, credentials, .pem, .key, .p12, secrets
Path patterns ~/.aws/credentials, ~/.kube/**, ~/.ssh/**, ~/.config/gh/hosts.yml, ~/.docker/config.json, ~/.gnupg/**
Content patterns GitHub tokens (ghp_, ghs_, github_pat_), AWS keys (AKIA…), PEM private keys, OpenAI keys (sk-…), Anthropic keys (sk-ant-…), generic password = / secret = assignments
High-entropy strings (opt-in) Random-looking tokens ≥16 chars with Shannon entropy >4.5 bits/char

High-entropy detection is opt-in (--entropy) because it can produce false positives on base64-encoded data, hashes, and other non-secret strings.

Suppressing false positives

Some files are intentionally tracked even though they look sensitive. Add them to [security] allow in haven.toml:

[security]
allow = [
  "~/.config/gh/hosts.yml",     # intentionally tracked — personal access token
  "~/.config/gcloud/**",        # managed by gcloud CLI; not a raw secret
  "~/.config/karabiner/**",     # keyboard config, no secrets
]

Patterns follow the same glob syntax as config/ignore:

Pattern Matches
~/.config/gh/hosts.yml Exact file
~/.config/gcloud/** Everything under ~/.config/gcloud/
*.example Any file with .example extension (basename only)

Integration with haven add

When you run haven add, haven scans the file before saving it. If sensitive patterns match, you're prompted:

warning: ~/.env may contain sensitive content (1 pattern(s) found).
  · Generic secret assignment (MEDIUM)
Track it anyway? [y/N]

Declining removes the file from source/ immediately — no partial state is left. Files in [security] allow bypass this prompt.

Using in CI

Add to your CI pipeline or as a pre-push hook:

# pre-push hook: .git/hooks/pre-push
#!/bin/sh
haven security-scan

Or in CI:

# .github/workflows/ci.yml
- name: Scan for secrets
  run: haven security-scan

haven security-scan exits 1 on findings, blocking the push or failing the CI job.

Handling 1Password and other secrets

The recommended approach is to never store secrets in the repo — use 1Password templates instead:

# source/dot_config/gh/hosts.yml.tmpl
github.com:
  user: alice
  oauth_token: {{ op(path="Personal/GitHub/token") }}

The destination file is written with the secret fetched live at apply time. Nothing sensitive is committed. See Templates & Secrets for details.

Supply chain protection for skills

haven also protects against supply chain attacks in AI skills. Every gh: skill source is pinned by SHA256 in haven.lock. A mismatch between the fetched content and the recorded SHA is a hard error:

# Intentionally upgrade a skill (clears and re-pins the SHA)
haven ai update pdf-processing

See AI Skills for details on the lock file.