Skip to content

gage 0.3.4

Choose a tag to compare

@github-actions github-actions released this 28 Oct 04:32
· 22 commits to master since this release

macOS app

Gage-0.3.4-macOS.zip is the desktop app: unzip it, drag Gage to Applications, and open it. No terminal, no install script. Apple Silicon, macOS 13 or later.

The app is not yet notarized, so on first open macOS will refuse a double-click. Right-click the app and choose Open, then confirm once; after that it opens normally. The command-line binaries below are unchanged for anyone who prefers them.


This release changes behaviour you will notice on the first bundle, and on
every pre-authorised flow. Read the first two sections before upgrading.

SENDER VERIFIED now requires a confirmation somebody actually performed

Three independent reviews — a security audit, a documentation audit and a
product critique — converged on one finding. SENDER VERIFIED meant "this key
is on your list". Every document described it as meaning "a human compared this
key's four word-pairs out of band". Those are different claims, nothing
recorded the second, and every route onto the list can be driven by software:
gage add from a chat window, quickstart from a pasted token, the MCP server
from an agent's say-so. A reviewer paired a stranger's key over MCP in two tool
calls, with no human anywhere, and it read SENDER VERIFIED.

There is now a confirmation record. It stores the fingerprint that was
compared, and re-checks it on every verdict, so it cannot drift from the key it
is about. A key that is merely on your list reads SENDER ON YOUR LIST, UNCONFIRMED — a new, eighth verdict.

Upgrading has a cost, and it is deliberate. Every existing contact drops to
unconfirmed. Nothing is withheld and nothing stops arriving — the key is still
attributable — but gage authority honours no grant under the new verdict, so
any pre-authorised flow stops until the contacts it names are confirmed. To
restore a machine to where it was:

gage contacts
gage fingerprint <name>        # prints the pairs, says if a record exists
gage confirm <name> '<the four pairs they read back to you>'

gage confirm takes the pairs you typed and checks them, so the record cannot
be written by something that did not do the comparison.

A file handed to you is now mail

gage unseal required --out, so a bundle someone handed you as a file was
written outside every directory the rest of gage looks in. The missing accept
step was the least of it: such a bundle was never witnessed, never journalled
as an arrival, never listed by gage inbox, and gage reply could not find
it
. Once the sender retired that key it read ARRIVAL UNRECORDED with its
contents withheld — although it had been read perfectly well beforehand, and
the journal still held the opened entry proving it.

gage unseal handoff.gageb          # receives: inbox, accept gate, reply
gage inbox

It now clears exactly the gates relay mail clears — a safe id, a verifying
signature, the replay witness — and lands unread in inbox/pending. --out
was a required argument, so no existing invocation changes behaviour.

--out keeps its old behaviour and now means inspect: it writes the files
and records nothing, and gage open on the result says so. Only delivery
writes a witness, deliberately — a witness is this machine's claim that it
received something, and the retired-key verdicts are decided by it. If
inspecting wrote one, peeking at a file would later earn a retired key the
milder verdict and reveal its contents.

Smaller things

  • gage authority says which grants are currently inert, and why. Found by
    dogfooding the upgrade above, which inerts every grant at once while the
    listing showed them exactly as it showed live ones.
  • --out may not write inside inbox/, sent/ or outbox/ — now enforced on
    gage unseal --out too, which never had it and could forge an accept.
  • An unreadable contacts.json stops the program instead of becoming an empty
    allowlist, which had turned every contact into a stranger and then overwritten
    the file on the next add.
  • gage add refuses to clear a retirement or a decline without --reinstate,
    and refuses a name retired under a different key.
  • Several documents claimed more than the code did, and now do not. The MCP
    pages no longer describe a self-pairing refusal that was never there; the
    README no longer says "nothing arrives from anyone you have not confirmed";
    seal --help no longer promises "nothing leaves this machine unsealed".
  • Verdicts are eight, and a unit test now fails if any document that tabulates
    them omits one. Three had shipped short lists.

Tests

1002 attack checks, 168 unit tests, 16 restore-drill checks, viewer
end-to-end 8/8, plus cargo audit. Every attack case is an attack that worked
or nearly worked.

Full Changelog: v0.3.3...v0.3.4