The admission gate ran the install scanner (dangerous fails) but nothing refused
a compiled binary, committed bytecode, or an archive hiding either — the shapes
the scanner cannot read. This adds that enforcement to pinned-source-validate.
- scripts/scan_plugin_payloads.py (stdlib-only, so the no-install validator and
third-party CI can run it): flags compiled binaries by magic header (ELF,
Mach-O, PE/MZ, WebAssembly — not by extension, which a rename defeats),
.pyc/.pyo bytecode (incl. sourceless/hash-forged caches that run instead of
the .py beside them), and archives whose members are not reviewable source.
Plain-text source bundles and inert assets (fonts, images) pass.
- plugin-catalog-ci.yml: after `hermes plugins validate`, each changed entry is
scanned; a finding fails it. An entry may list `attested_binaries:` paths,
each verified with `gh attestation verify --repo <repo> --source-digest <sha>`
against the pinned commit; verified paths are dropped before the scan, any
other binary still fails. Repo-controlled filenames are newline-stripped in
the log so none can forge a workflow command.
- validate_plugin_catalog.py: `attested_binaries` is a known key, shape-checked
as a list of relative paths.
- Tests: unit tests for the detector and two new workflow-driven bypass cases
(bundled .exe, committed .pyc) in the confinement harness, which runs the real
`run:` block.
Full-content re-sweep of all 543 pins: only tabro carries a native binary (it is
delisted in the companion PR). Three entries (crawl4ai, hermes-vision-inline,
mermail) commit __pycache__/*.pyc build litter and would fail rule 17 on their
next pin bump — pre-existing, not touched here.