Make the product buyable and the open-source claim true. Licence system, end to end. license.rs was well-designed dead code; wire it up: an Ed25519-signed token (same key and verify-before-parse discipline as definition packs), `hound license install`, houndd loads and verifies at boot, and the execution gate and full supply-chain feed now gate on Capability checks. Verification failing always degrades to Free, never to a locked-out security tool; an expired licence downgrades with the reason shown. Adds tools/issue-license.py. Hound Linux threat pack. 34 curated YARA rules — miners, IoT/DDoS bots, backdoors, rootkits, ransomware, webshells, droppers, reverse shells — shipped through a new signed rules-pack channel (.rpack) alongside the definitions feed. Every rule is ELF- or size-anchored and keyed on family strings, never syscalls; the builder refuses to sign a pack that matches a system binary (the goodware gate caught two bad rules), and a regression test proves every rule fires on a sample and stays quiet on a document about malware. Action signature verification. The composite action claimed Ed25519 verification "against the same signed manifest the desktop agent uses" but only compared a same-host sha256. It now fetches latest.json, verifies the Ed25519 signature over the canonical release statement against the pinned release key, and installs the checksum from the verified manifest. Licence resolved to Apache-2.0: Cargo.toml, a real LICENSE file, README. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
167 lines
6.1 KiB
Markdown
167 lines
6.1 KiB
Markdown
# Hound Antivirus
|
|
|
|
A premium, freemium antivirus for Linux. One engine, three faces:
|
|
a Rust daemon (`houndd`), a CLI (`hound`), and a Tauri GUI with a
|
|
system-tray sentinel that changes color with your security state.
|
|
|
|
Built for the distros people actually run: **Ubuntu, Debian, Linux Mint**,
|
|
and anything else that ships ClamAV.
|
|
|
|
## Repository layout
|
|
|
|
```
|
|
antivirus/
|
|
├── Cargo.toml # Rust workspace
|
|
├── crates/
|
|
│ ├── hound-api/ # shared wire types + socket client (daemon/CLI/GUI all use it)
|
|
│ ├── houndd/ # the daemon: Unix-socket API over a pluggable engine
|
|
│ └── hound/ # CLI client
|
|
├── assets/icons/ # dog-head brand mark + 4-state tray ladder
|
|
└── gui/ # Tauri 2 desktop app (system tray + scan UI)
|
|
```
|
|
|
|
## Architecture
|
|
|
|
```
|
|
houndd (Rust daemon — the engine)
|
|
┌──────────────────────────────────┐
|
|
│ ScanEngine trait │
|
|
│ ├─ L1 ClamAV signatures (now) │
|
|
│ ├─ L2 Curated threat packs(Pro)│
|
|
│ ├─ L3 Behavioral monitor (Pro) │
|
|
│ └─ L4 Supply-chain checks(Pro) │
|
|
└──────────────┬───────────────────┘
|
|
Unix socket (JSON-RPC, line-delimited)
|
|
┌───────────┼───────────┐
|
|
hound CLI GUI (Tauri) future modules
|
|
```
|
|
|
|
The daemon is the only process that touches a scanning engine. CLI and GUI
|
|
are thin clients — so future suite tools (firewall, updater, …) plug into
|
|
the same socket.
|
|
|
|
### Swapping the engine (the ClamAV seam)
|
|
|
|
ClamAV is a **temporary** dependency. Everything ClamAV-specific — version
|
|
probe, signature freshness, the `clamscan` subprocess + output parsing,
|
|
`freshclam` — lives in one file behind a four-method trait:
|
|
|
|
```
|
|
crates/houndd/src/engine.rs
|
|
trait ScanEngine { name; probe; scan; update }
|
|
struct ClamAvEngine // today
|
|
const ENGINE: ClamAvEngine // ← flip this line when the native
|
|
// engine lands; nothing else in the
|
|
// daemon, CLI, GUI, or wire API moves
|
|
```
|
|
|
|
The wire stays engine-agnostic: `Status.engine` names the implementation
|
|
(`"clamav"` today) and `Status.db` carries what any signature store has —
|
|
a file name and a timestamp. When our own Rust engine ships, it's a new
|
|
`ScanEngine` implementation, a one-const flip, and the tray/CLI/GUI simply
|
|
start reporting the new engine name.
|
|
|
|
## Icon system
|
|
|
|
The brand mark is a solid dog head (`assets/icons/hound.svg`), a single
|
|
flat fill. It ships in two treatments:
|
|
|
|
- **Brand ladder** `hound-{16,22,24,32,48,256}.png` — native periwinkle
|
|
`#9896E0`, for the window icon, About box, and marketing.
|
|
- **Tray-state ladder** `state-<name>-{16,22,24,32,48}.png` — the same
|
|
path re-tinted per security state, for the system-tray sentinel:
|
|
|
|
| State | Fill | Meaning |
|
|
|---|---|---|
|
|
| `protected` | `#22C55E` green | up-to-date / protected / clean |
|
|
| `scanning` | `#F59E0B` amber | scan in progress / signatures need update |
|
|
| `threat` | `#EF4444` red | infection found |
|
|
| `paused` | `#6B7280` gray | real-time monitor off |
|
|
|
|
Green is the *good* state; amber is *work in progress*, never a failure.
|
|
|
|
## Quickstart (development)
|
|
|
|
Prereqs: Rust (see `rust-toolchain.toml`), Node 20+, ClamAV, and the
|
|
Tauri system libs (`libwebkit2gtk-4.1-dev`, `libgtk-3-dev`, `libayatana-appindicator3-dev`).
|
|
|
|
```sh
|
|
# 1. Signatures (needs the clamav freshclam DB)
|
|
sudo freshclam
|
|
|
|
# 2. Daemon (terminal 1)
|
|
cargo run -p houndd
|
|
|
|
# 3. Scan (terminal 2)
|
|
cargo run -p hound -- status
|
|
cargo run -p hound -- scan ~/Downloads
|
|
|
|
# 4. GUI
|
|
cd gui && npm install && npm run tauri dev
|
|
```
|
|
|
|
### Verifying the engine with the EICAR test file
|
|
|
|
EICAR is the industry-standard 68-byte test signature — every AV that
|
|
works will flag it. Generate it and scan it:
|
|
|
|
```sh
|
|
printf 'X5O!P%%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > /tmp/eicar.com
|
|
cargo run -p hound -- scan /tmp/eicar.com
|
|
# expect: exit code 1, "Eicar-Test-Signature FOUND"
|
|
```
|
|
|
|
### Updating signatures
|
|
|
|
`hound update` wraps `freshclam` (trying `sudo freshclam` first, since
|
|
plain-user runs can't write `/var/lib/clamav` and `/var/log/clamav`). The
|
|
GUI's "Update Signatures" button drives the same RPC and shows the log.
|
|
```sh
|
|
cargo run -p hound -- update # or: hound update --json
|
|
```
|
|
|
|
## The GUI (`gui/`)
|
|
|
|
A Tauri 2 desktop app — a thin view over the *same* `houndd` socket the
|
|
CLI uses (via the shared `hound-api` client), so the window and the
|
|
command line never disagree about your security state.
|
|
|
|
```
|
|
gui/
|
|
├── dist/ # the front-end (vanilla HTML/CSS/JS, premium dark shell)
|
|
└── src-tauri/ # Tauri 2 shell + system-tray sentinel
|
|
```
|
|
|
|
The tray sentinel swaps the 4-state icons (green/amber/red/gray) as your
|
|
state changes; the window shows a live protection hero, a scan progress
|
|
bar, a results table, and the signature-update log.
|
|
|
|
Build it:
|
|
```sh
|
|
cd gui
|
|
npm install
|
|
npm run tauri dev # dev with hot reload
|
|
npm run tauri build # → .deb in src-tauri/target/release/bundle/
|
|
```
|
|
|
|
## Git conventions
|
|
|
|
- Branch `main` is deployable; small, focused commits.
|
|
- **No hardcoded secrets.** For pushes, the bot token lives in a repo-local
|
|
credential file (never tracked):
|
|
|
|
```sh
|
|
git config credential.helper 'store --file=.git/.git-credentials'
|
|
chmod 600 .git/.git-credentials
|
|
echo 'https://<user>:<token>@git.joelovestech.com' >> .git/.git-credentials
|
|
```
|
|
|
|
- Commits: imperative subject, ≤ 72 chars. Example: `houndd: add line-delimited JSON-RPC socket API`
|
|
|
|
## License
|
|
|
|
Apache-2.0. The whole agent — daemon, CLI, GUI, supply-chain suite, MCP
|
|
server — is open source; see [LICENSE](LICENSE). The paid tiers are not a
|
|
different codebase: Pro and Fleet buy the signed definitions feed, the
|
|
curated threat pack and (for Fleet) central management, served against a
|
|
licence. The binary you can read is the binary we ship.
|