HOL Guard 2.1: 51,000 Test Cases, HMAC-Backed Reconnect, and a New Command Classification Engine

HOL Guard 2.1: 51,000 Test Cases, HMAC-Backed Reconnect, and a New Command Classification Engine

HOL Guard 2.1 ships a 51,000-case command classification corpus, HMAC-backed dashboard reconnect, signed Codex hook manifests, DNS-pinned archive downloads, and a typed GitHub capability model — all open source, canary-tested on TestPyPI.

5 min read992 words

The Release

HOL Guard 2.1 changes 575 files, adds 107,000 lines, and ships a 51,000-case command classification corpus that assigns every AI-generated shell command a security floor before the tool runs it. Every layer of the stack changed — the local daemon, the Codex hook pipeline, the dashboard UI, CI, the test harness.

Three things define this release:

  • A six-level action lattice (allow, warn, review, require-reapproval, sandbox-required, block) backed by a 51,000-case decision-diff corpus. Zero known gaps. Zero lowered decisions. The corpus ships with the code.
  • HMAC-backed dashboard reconnect that survives daemon restarts without dropping the trust relationship between the dashboard and its local server. Mutual challenge-response with replay protection.
  • Codex hook manifest signing that cryptographically binds hook identity so a compromised workspace cannot silently swap which hooks Guard trusts.

Behind those headlines: restricted archive downloads with DNS pinning, structured GitHub command capability modeling across shell/REST/GraphQL, cross-platform CI (Linux, macOS, Windows), a dashboard migration from npm to bun, and a TestPyPI canary pipeline that verifies installed-origin proof before any stable tag.

Command Classification: 51,000 Cases, Six Floors

Guard 2.1 replaces the previous allow/block binary with a six-floor action lattice. Every tool invocation gets exactly one floor. No configuration file can lower it.

  • allow — safe, no interaction
  • warn — notify but proceed
  • review — surface in the approval center
  • require-reapproval — block until developer approves in the dashboard
  • sandbox-required — isolate before touching the host
  • block — refuse execution

The corpus lives in tests/fixtures/guard-command-corpus/. Each of the 51,000 cases maps a command to its expected floor. CI runs a decision-diff report against every case on every push. A merge always requires review. A credential read always requires reapproval. A Guard configuration modification always blocks.

Classification rules sit in command_critical_floors.py (490 lines): merge, release, history, delete, secret, access, workflow, content, and dynamic mutations each get a fixed floor.

Dashboard Reconnect: HMAC Challenge-Response

Guard's dashboard connects to a local daemon over localhost. When the daemon restarts — after an update, a crash, a reboot — the old connection model had no way to confirm it was talking to the same installation.

The 2.1 protocol (dashboard_reconnect.py, 416 lines):

  1. POST /v1/update/reconnect/prepare — the dashboard asks the current daemon for a signed authorization. The daemon persists a reconnect_id, installation fingerprint, and HMAC-bound challenge to Guard's home directory.
  2. The daemon restarts. The dashboard probes candidate ports until it finds a /healthz endpoint.
  3. POST /v1/update/reconnect/challenge — the dashboard challenges the recovered daemon. The daemon checks that the authorization is still fresh, then returns a server-side HMAC proof.
  4. The dashboard verifies the server proof, then sends POST /v1/update/reconnect/verify with its own client proof. The daemon checks the replay cache.
  5. Only after mutual verification does the dashboard resume status polling.

Every challenge binds to a specific installation ID, guard home ID, and compatibility version. Replays fail. Cross-installation challenges fail. Port mismatches fail. The dashboard test suite backs this with 302 lines of security-specific e2e tests (guard-update-reconnect-security.test.ts).

Hook Manifest Integrity and Archive Safety

Codex hooks intercept tool calls inside the developer's own process. Before 2.1, hook configuration lived in plain workspace files — an attacker with filesystem access could modify the identity record and redirect Guard's inspection pipeline.

Guard 2.1 introduces signed hook manifests (codex_hook_manifest.py, 495 lines). Each manifest carries the hook's identity, expected payload shape, and an HMAC signature from a private key stored in Guard's home directory — outside the workspace, with restrictive permissions and atomic writes. Guard verifies the signature at load time. A failed check logs a tamper event and refuses the hook.

Archive safety follows the same trust-nothing principle. Agents download archives frequently — model weights, package tarballs, training data. 2.1 routes every archive download through a five-module pipeline that enforces HTTPS-only transfers, DNS pinning, redirect limits (max 3, same-origin after the first), and bounded streaming with a size cap — then scans the result in a sandbox with no network access and dropped capabilities before the host filesystem ever sees it. Incomplete downloads land in temp; only verified completes get an atomic rename into the workspace.

GitHub Capability Modeling

gh pr merge, gh release create, gh secret set — GitHub CLI commands are among the most common things an AI agent runs and among the riskiest. Before 2.1, Guard pattern-matched against command strings. A reformulated command could slip past.

2.1 ships a typed capability model spanning six modules:

  • github_capability_contract.py (313 lines) — maps every GitHub operation to its required capability and security floor
  • github_rest_capabilities.py (304 lines) — REST API path classification
  • github_graphql_capabilities.py — GraphQL operation classification
  • github_shell_capabilities.py (497 lines) and github_shell_bindings.py (489 lines) — shell binding model mapping gh commands, flags, and arguments to capabilities
  • github_command_capabilities.py — unified classification entry point
  • verified_github_reads.py (362 lines) — proven-read pattern allowing safe gh reads through --json formatters

gh repo delete is blocked regardless of spelling. gh pr view --json number,title is allowed. gh issue create requires review. Classification follows what the command does — not what it looks like.

CI, Canary Pipeline, Dashboard

Guard's build and release infrastructure grew substantially in 2.1:

  • Cross-platform CI across Linux, macOS, and Windows (Python 3.10–3.13). uv 0.9.26 pinned with its SHA-256 in the CycloneDX SBOM.
  • TestPyPI canary pipeline (publish.yml, now ~930 lines): every release-branch push produces a unique per-PR canary wheel, verifies byte equality against the build artifact, installs on a clean environment, runs the full 51K-case corpus, and proves installed origin on all three OS targets.
  • Dashboard migrated from npm to bun 1.3.14. Four new Playwright e2e specs cover reconnect, command activity, approval scope, and protection health — all targeting the installed wheel, not a dev checkout.
  • Command activity API (command_activity_api.py, 474 lines) with privacy controls, authenticated totals, filters, detail views, and execution-proof copy.

Installing It

The 2.1 alpha ships to TestPyPI for canary testing. Stable releases, Docker images, and Homebrew updates follow.

pip install --index-url https://test.pypi.org/simple/ hol-guard

The repository is github.com/hashgraph-online/hol-guard. Apache 2.0.

Continue reading

All posts