keyhog 0.5.40

keyhog: detects leaked credentials in source trees, git history, and cloud storage
Documentation
[package]
name = "keyhog"
description = "keyhog: detects leaked credentials in source trees, git history, and cloud storage"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
authors = ["Santh Project <security@santh.dev>"]
license.workspace = true
repository = "https://github.com/santhsecurity/keyhog"
homepage = "https://github.com/santhsecurity/keyhog"
documentation = "https://docs.rs/keyhog"
keywords.workspace = true
categories.workspace = true
readme = "README.md"

[package.metadata.santh]
status = "alpha"

[lib]
path = "src/lib.rs"

[[bin]]
name = "keyhog"
path = "src/main.rs"

[features]
# Default = full experience. Only gpu, simd, and binary (Ghidra) are opt-in
# because they require heavy compile-time deps or system libraries.
# cargo install keyhog gives you EVERYTHING else.
default = [
    "keyhog-scanner/default",  # ML, entropy, decode-through, multiline
    "git",                      # Git source backends
    "web",                      # URL scanning (JS/sourcemap/WASM)
    "github",                   # GitHub org scanning
    "s3",                       # S3 bucket scanning
    "docker",                   # Docker image scanning
    "verify",                   # Live credential verification
    "tui",                      # `keyhog tui` live-scan dashboard
    "mimalloc",                 # thread-caching global allocator (scan parallelism)
]
# Thread-caching global allocator for the CLI binary. The scan hot path runs
# one Rayon worker per core, each allocating regex DFA-cache scratch and
# per-match Strings; glibc's arena lock serialises those allocations (visible
# as kernel `osq_lock` contention in `perf`, and as sub-linear thread scaling).
# mimalloc gives every thread its own heap, removing the arena lock. The binary
# chooses this; the libraries stay allocator-agnostic. Disable with
# `--no-default-features` (the `ci`/`portable` profiles that omit it still build).
mimalloc = ["dep:mimalloc"]
# Lean CI aggregator build: the full default surface minus the GPU dispatch
# stack (`keyhog-scanner/ci-lean`). Used by ci.yml's integration-tests job on
# GPU-less runners; runners-nightly keeps `gpu` on real GPU hosts.
ci-lean = [
    "keyhog-scanner/ci-lean",
    "git",
    "web",
    "github",
    "s3",
    "docker",
    "verify",
    "tui",
]
# Unused Cargo flag — use `keyhog scan --fast` at runtime for pre-commit speed.
fast = []
# macOS release builds: every keyhog-scanner data feature, no system-lib deps
# (no Hyperscan / Ghidra / CUDA). Workflows pass just `--features portable`
# instead of having to enumerate `keyhog-scanner/...` per release.
portable = [
    "keyhog-scanner/ml",
    "keyhog-scanner/entropy",
    "keyhog-scanner/decode",
    "keyhog-scanner/multiline",
    "git",
    "web",
    "github",
    "s3",
    "docker",
    "verify",
    "mimalloc",
]
full = [
    "keyhog-scanner/ml",
    "keyhog-scanner/entropy",
    "keyhog-scanner/decode",
    "keyhog-scanner/multiline",
    "git", "web", "github", "s3", "docker",
    "verify",
    "binary",
    "mimalloc",
]
# Maximally-light CI / embeddable profile. Use as:
#   cargo install --no-default-features --features ci
# Drops every heavy axis a CI run never needs: NO Hyperscan (`simd` - kills the
# ~1.7s cold-start; the AC+regex path is faster for keyhog's <2K patterns anyway),
# NO GPU/vyre drivers, NO live verification, NO TUI, NO Ghidra, and NO git/web/
# cloud source backends (the always-on filesystem + stdin path covers
# `keyhog scan .` / `keyhog scan --stdin`, which is how CI scans a checked-out
# tree). Keeps the full embedded detector corpus + ML + entropy + decode-through +
# multiline + token efficiency. Instant start, smallest binary - the profile CI
# integrations should use. Git-history / cloud scanning is opt-in on top
# (`--features ci,git`) or via the fuller `portable` profile.
ci = [
    "keyhog-scanner/ml",
    "keyhog-scanner/entropy",
    "keyhog-scanner/decode",
    "keyhog-scanner/multiline",
]
git = ["keyhog-sources/git"]
github = ["keyhog-sources/github"]
s3 = ["keyhog-sources/s3"]
docker = ["keyhog-sources/docker"]
binary = ["keyhog-sources/binary"]     # Ghidra decompiler (requires Ghidra installed)
web = ["keyhog-sources/web"]
verify = ["keyhog-verifier/live"]
gpu = ["keyhog-scanner/gpu"]           # wgpu compute shader inference (heavy)
simd = ["keyhog-scanner/simd"]         # Vectorscan/Hyperscan SIMD regex (system lib required)
cuda = ["keyhog-scanner/cuda"]         # no-op alias: CUDA is the primary GPU backend on Linux, always compiled + runtime-loaded
# Interactive TUI scan dashboard. Pulled in by default; can be turned
# off in size-constrained builds via `--no-default-features`. Adds
# ratatui + crossterm to the dependency closure.
tui = ["dep:ratatui", "dep:crossterm"]

[dependencies]
keyhog-core = { workspace = true }
keyhog-scanner = { workspace = true, default-features = false }
keyhog-verifier = { workspace = true, optional = true }
keyhog-sources = { workspace = true, default-features = false }
clap = { workspace = true }
clap_complete = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
anyhow = { workspace = true }
rayon = { workspace = true }
toml = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
chrono = { workspace = true }
dirs = { workspace = true }
notify = { workspace = true }
# Used by `baseline.rs::save` for atomic-rename writes via
# `NamedTempFile::persist()` — same pattern used by merkle and
# calibration. A mid-write crash on `--update-baseline` would
# otherwise leave a corrupt JSON the next run can't parse.
tempfile = { workspace = true }
# `keyhog update` self-updater: GitHub releases API + raw-binary download.
# reqwest is already in the dep tree via the (default-on) verifier; listing
# it here lets the updater issue its own GET without routing through the
# verification client. The atomic running-binary swap uses a same-dir
# rename (Unix lets you replace a running exe's file) - no extra crate.
reqwest = { workspace = true }
# Thread-caching allocator (see the `mimalloc` feature above). Optional so
# `--no-default-features` builds (and any platform where the C build is
# undesirable) drop it cleanly and fall back to the system allocator.
mimalloc = { version = "0.1", optional = true, default-features = false }
# Verify-only minisign: `keyhog update` checks the release binary's
# signature against the embedded public key before self-replacing.
minisign-verify = { workspace = true }
# Pulled in by the `keyhog tui` subcommand for the live-scan demo.
# Both gated behind the `tui` feature so portable builds (Windows,
# macOS via `--no-default-features --features portable`) still build
# without paying the dep cost.
ratatui = { workspace = true, optional = true }
crossterm = { workspace = true, optional = true }

[target.'cfg(unix)'.dependencies]
# Used only by `reset_sigpipe()` in main.rs to restore the default
# SIGPIPE handler. Without this, `keyhog scan | head` produces a
# spurious BrokenPipe error instead of exiting cleanly when the
# downstream consumer closes its end of the pipe.
libc = { workspace = true }

[dev-dependencies]
keyhog-core = { workspace = true }
keyhog-scanner = { workspace = true, default-features = false }
keyhog-sources = { workspace = true, default-features = false }
serde_json = { workspace = true }
serde_yaml = { workspace = true }
tempfile = { workspace = true }
regex = { workspace = true }
toml = { workspace = true }
# Property-based suite (tests/property.rs). These proptests reference `proptest`
# but the dep was missing — the whole property/ dir was orphaned (empty mod.rs)
# so it never compiled and the gap stayed hidden. Pinned via the workspace.
proptest = { workspace = true }
# Mock GitHub releases API for the installer/update lifecycle suite: drive the
# real binary's release-resolution path against deliberately hostile responses
# (malformed JSON, 500s, missing assets) with zero network.
httpmock = { workspace = true }