Five fixes, no new tools. Three of them are about the same failure shape this project cares most about — a no-op reported as success — and two are bookkeeping.
Fixed
- The CLI ran nothing through the
binlink.cdmon --helpvianpm linkornpm install -gprinted nothing and exited 0: Node resolves the entry point's symlink, soimport.meta.urlnever matched the linkedprocess.argv[1]. The main-module check now resolves both sides through the filesystem. db_querylet two writes through.EXPLAIN ANALYZE UPDATE ...executes the statement it explains on MySQL 8, andSELECT ... INTO OUTFILEwrites a file on the database host. Both are now refused like any other write; plainEXPLAINis still allowed.- An expired phpMyAdmin session was a silent success. After 24 idle minutes phpMyAdmin answers a statement with its login page — status 200, no error, no rows — so the next
db_executefrom a long-lived server was reported as applied with nothing affected. The client now recognises that page, logs in again and re-sends the statement once; if the login page comes back again, the statement fails by name. - The upload dry run counted characters, not bytes. A file with accents or emoji previewed at one size and landed at another. Both now report UTF-8 bytes.
- Failed uploads and deletes now reach the audit log, as
failedentries carrying the path and the error, matching whatdb_executealready recorded.
No breaking changes. See the CHANGELOG, docs/safety.md and docs/phpmyadmin.md.