Commit graph

3 commits

Author SHA1 Message Date
dev
cb943c66c4 0.1.2: hound update brings the whole machine current
Definitions and the application were two separate acts with two
different mechanisms, and only one of them had a command. `hound
update` now does both:

  sudo hound update                definitions, then offer the app
  sudo hound update -y             both, unattended
  hound update --check             what is available, install nothing
  sudo hound update --definitions-only

Definitions run first and independently: a release check that fails —
laptop offline, host down — is a warning, not a failed command. The
definitions half is what matters between releases and it either worked
or it did not, regardless of what the manifest server did.

The app half prompts unless given --yes, because definitions are
verified before they are parsed while replacing the running binary is a
larger step. Non-interactive callers never block on a read: they are
told to pass --yes and exit cleanly.

`release.check` is classified read-only, so any member of the `hound`
group can ask whether they are current — it changes nothing and reveals
nothing the website does not. Installing still requires root and says
so.

Verified end to end on a real machine: a 0.1.1 install discovered
0.1.2, verified the signed manifest, checked the SHA-256, staged it
root-owned and installed it through apt, unattended.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 12:10:20 -05:00
Hound
6beb73771a hound-supply: the supply-chain and agent-era scanner
Phase 4's detection core, as a standalone crate. This is the part with no
competitor on Linux, and deliberately the part with no Linux in it —
file parsing and logic only, no fanotify, no /proc, no eBPF — so the
macOS and Windows port is weeks rather than a second product.

Five detectors, 88 tests:

  pickle        GLOBAL/STACK_GLOBAL walk over .pt/.ckpt/.pkl/.joblib.
                torch.load runs a stack machine; a model file is a
                program and downloading weights is a code-execution
                decision.
  injection     Instructions aimed at a coding agent in CLAUDE.md,
                AGENTS.md, .cursorrules, copilot-instructions.
  installscript preinstall/postinstall hooks that curl|sh, decode and
                run, reach for credentials, or install persistence.
  typosquat     Damerau-Levenshtein against popular names, plus
                slopsquat detection: new + near-zero downloads + one
                edit from something popular is the signature of a name
                a model invented and somebody then registered.
  mcp           Servers fetched unpinned at launch, handed secrets, or
                pointed at $HOME or credential paths.

Wired through `supply.sweep` on the socket and `hound supply-chain
<path>`, which exits 1 on a critical so it drops into CI.

Three things worth recording:

* Scoring is by independent category, not by keyword count. One
  suspicious phrase is a phrase; two categories at once is an attack.
  A file that only says "ignore previous instructions about formatting"
  is a warning, not a critical.

* Proximity matters more than presence. The first version flagged an
  entirely ordinary conventions file, because it mentioned ".env" in
  one paragraph and "prefer small commits" in another. A credential and
  a movement verb now have to appear within a sentence of each other.
  The test that caught it is kept as the regression.

* Pickle call detection has to come out of the opcode walk, not a byte
  search. REDUCE, INST and OBJ are the ASCII letters R, i and o, which
  also occur inside every string the stream carries — searching raw
  bytes finds the o in "os" and reports a call that never happens,
  turning every warning into a critical.

Every finding carries a plain-language explanation and a next step, and
there is a test asserting explanations do not leak rule identifiers or
jargon. The audience includes people who cannot triage a YARA match and
should never be shown one.

Verified against a demo project holding a squatted @vue plugin with a
curl|sh postinstall, a poisoned CLAUDE.md in a vendored repo, an
unpinned MCP server holding a GitHub token, and a pickle calling
os.system — four criticals and one warning, while the legitimate
CLAUDE.md, the real express manifest and the properly-scoped MCP server
beside them stayed clean.

189 tests pass across the workspace.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 23:48:48 -05:00
2cf41ce3bd Rust engine + CLI over ClamAV Unix socket
- hound-api: shared wire types (Status/ScanRequest/ScanResult/Found)
  + line-delimited JSON-RPC client used by both clients
- houndd: daemon binding a Unix socket, dispatching status/scan to
  ClamAV, parsing per-file results, deduping --allmatch hits
- hound: clap CLI (status / scan --json), colored human output,
  exit codes 0=clean 1=threats
- workspace scaffolding: toolchain, gitignore, env example, editorconfig
2026-08-20 16:59:14 -05:00