Skip to content

NockGuard v0.6.0: fail-closed audit, local approver, Wall in the release

Choose a tag to compare

@miraanocktech miraanocktech released this 13 Oct 03:05
· 22 commits to main since this release
4945590

NockGuard v0.6.0 refuses tool calls when it cannot write its signed audit record, adds a local approver for held calls, and ships the Wall in the release archives with NockLock events in the same stream.

Upgrade notes: this release has breaking changes. Read the Breaking section before upgrading. Anything that counts audit rows should expect the new dispatch row. nockguard init writes a new starter policy, and existing policy files are not touched.

Install on macOS: brew upgrade nocktechnologies/tap/nockguard (installs nockguard and nockguard-wall). Linux and macOS archives with SHA256SUMS are attached below.

Breaking

  • Local nockguard proxy and mcp-listen (and mcp-http) now refuse tool calls when a required audit write fails, whenever auditing is enabled. The failure latches: every later call is refused until the trail is fixed and reopened with a verified signing key. Pass --audit-best-effort to get the old forwarding back; startup prints a warning. status, doctor and the Wall show audit failing: calls refused while a failure is outstanding.
  • nockguard proxy and mcp-listen now write a dispatch audit row before they forward an allowed tools/call request, when auditing is on and --audit-best-effort is not set. Each such call has one more row than in 0.5.0. Denied calls, other methods and mcp-http write no dispatch row, and mcp-gateway already wrote one. Anything that counts rows or matches decisions should expect dispatch.
  • nockguard init writes a different starter policy. The agent is coder (was my-agent), it allows read_file and read_text_file and denies write_file, default stays mode: deny, and audit.enabled: true is on (it was commented out). The old ask rules and wildcard allows are gone. Run keygen --agent coder before the first proxy run so the audit trail is signed. Existing policy files are not touched, and init still refuses to overwrite one without --force.
  • The Wall now reads the agent's public key with the same resolver as nockguard verify --agent: the NOCKGUARD_AGENT_<NAME>_ED25519_PUB variable first, then ~/.nockguard/keys/<name>.pub. A Wall that relied on a key being absent will now verify against the file. /verify reports PROTECTED only for a non-empty trail that its signed checkpoint fully covers; empty, unconfigured, unavailable and unanchored trails are shown as such.

Added

  • Local approver for ask verdicts, with no network: set NOCKGUARD_APPROVER=local and decide held calls with nockguard approvals list|approve|deny (prune removes dead sockets left by crashed proxies). Held calls wait on a 0600 unix socket in a 0700 approvals directory, one <pid>-<random>.sock per proxy, removed on exit, and are audited as approval-granted / approval-denied with the approver local:<uid>. The listing shows id, agent, tool, reason and age, never arguments. The approver does not start, and ask fails closed, if the directory or socket permissions, ownership or type are wrong. A same-uid agent can still approve its own calls; see the README trust boundary.
  • Live Wall shows NockLock and NockGuard in one stream. nockguard-wall --lock-db <events.db> reads a NockLock log read-only (file, network and secret fence events, blocked and passed), labeled LOCK / GUARD and colored by outcome, decision only. --lock-pub-env names the NockLock public key (default NOCKLOCK_AUDIT_ED25519_PUB). --demo cannot be combined with --lock-db.
  • Per-session signed-proof badge on the Wall (GET /sessions): the same verdict as nockguard verify --session (PROTECTED / TAMPERED / UNSIGNED / UNVERIFIABLE / NO_ROWS / UNANCHORED) with both key fingerprints. A missing key is UNVERIFIABLE, never green. A Lock log over 100,000 events is UNVERIFIABLE, too large. An unreadable Lock row shows as UNPARSEABLE and makes its session UNVERIFIABLE; the rest of the batch still shows.
  • nockguard wall subcommand. It starts nockguard-wall from beside the CLI or from PATH and forwards flags and signals. nockguard-wall now ships in the Linux and macOS release archives, and a standalone nockguard-wall install keeps working.
  • nockguard status --agent <name> and doctor report a required audit write failure; status accepts --audit <path> for custom trail paths.
  • A Linux CI check runs the README quickstart end to end (init, keygen, proxy, verify) against a local MCP stub, with a successful read, a blocked write and signed allow and deny rows.

Changed

  • /export CSV and JSON gain a trailing source column / field (GUARD or LOCK). With --lock-db, each source keeps its own 500-row cap, and the X-NockGuard-Lock-Verification response header is ok, unsigned (no Guard key, so nothing is verified) or unavailable (no Lock snapshot, so no Lock rows). The PROOF export remains NockGuard rows only.
  • The README quickstart uses the coder agent and a concrete demo path, matching nockguard init.
  • Documentation claims now match shipped behavior, and a repository map and the 1.0 contract are added under docs/.

Fixed

  • macOS: the local approver socket path now fits the 104 byte sun_path limit. When ~/.nockguard/approvals would be too long, it falls back to a private per-user directory under /tmp.
  • macOS 26.5: two nockguard processes starting at once on a fresh machine no longer fail with "opening key lock ... no such file or directory".

Known limits

  • With stdio, a response that arrives ahead of an earlier pending call can be released before its deferred decision row is written. The dispatch row is durable first. If that later write fails, the latch refuses every later call and status reports the failure.
  • The failure marker is per trail, not per process or per agent. Every proxy writing the same trail sees it.
  • An unsigned trail has no verified reopen, so nothing clears its failure marker short of choosing --audit-best-effort. Sign the trail to get the repair path.