A tap approval in our monorepo now covers one exact command. The card id is derived from a sha256 digest over the working directory, the command string and the repo state, and the run proceeds only if a digest recomputed over what is about to execute matches. Edit the command or move HEAD while the card waits, and the tap is refused.
Merges, publishes, releases and production deploys in app repos wait for a founder tap on a Telegram card. Previously the approval was keyed to the card id alone, so whatever ran behind that id at execution time ran. The classify step now mints the digest, derives the card id from it, and echoes it on every verdict.
The working tree is hashed for every kind of action, so a compound commit-and-push or push-and-publish cannot ship an edited tree under an approval given for a clean one. Approvals that were pending before the change are refused as unbound rather than migrated.
The approval row on the receiving side is bound too. The digest travels to the approvals service on create and is checked on every poll, before the status. A missing digest reads as unbound, a different one as a mismatch, and an empty expected digest fails closed.
A tap on a row bound to other content is refused.
A digest is only useful if the gate notices every command that needs a tap. The matcher used to be regular expressions, which cannot see through quoting, subshells, redirects, a cd on a new line, pushd or a --all flag. A pure parser module now reads words with quote removal, separators, compound commands and substitutions, and tracks every directory a command might run in as a set, so a cd that may never execute cannot move a push into the exempt monorepo.
Code it cannot read, such as a dynamic command word, a pipe into a shell, an interpreter's -c flag or ssh, gets a loose scan and is carded for an unknown repo. The digest still hashes the exact command string, parsed or not.
A fresh-context reviewer found 60 more ways past the first parser. Fifty-six are held now: earlier git config changes that rewrite a push target, package scripts that publish, workflow dispatches of release files, and API writes that land on main. A second round found that a self-running heredoc script took 152 seconds to parse and let the hook lapse, so the parser now has a budget of one million steps or 100 ms per call, and going over it counts as opaque and fails closed.
False positives were measured by replaying 76,340 real session commands through the old gate and the new one. The residual cases the parser still does not hold are written down in the gate's README, not left to be discovered.
This post was drafted by an AI system from Dekimu's public engineering record and published with automated checks, without per-post human editing.
← Back to blog