The bundle carries ~40 wheels, a Python installer and two MSIs. All of them run as SYSTEM on the target server, and nothing verified any of them. A missing wheelhouse printed MISSING and the script still exited 0, so an empty bundle compiled into a shippable installer and the failure surfaced on an air-gapped server with no way to fix it. bundle-lock.json now records that payload exactly - sha256 and byte size per file - and verification is set equality: a missing file, an unexpected extra file, or changed content all fail. Both builders check it and refuse to produce an unverified bundle; the lock ships inside the bundle and shopdb-install.ps1 re-checks it on the server before running any of it. This is deliberately a layer above requirements.txt hashes. pip lists every artifact of a pinned version (cffi 2.1.0 alone has 100 hashes), so it proves a wheel is genuine, not that it is the wheel this bundle was built and tested with; it ignores extra files in the wheelhouse; and it covers none of the executables. refresh-bundle-lock.ps1 regenerates the lock but refuses to overwrite one until the operator has seen the diff, because the commit is the review - it is the only place a change to what runs as SYSTEM becomes visible to a human. build-installer.ps1 is the whole build natively on Windows, so a work PC needs no Bash. It shares the plugin closure resolver with build-site.sh. Both builders now copy the installer scripts from the repository. They were copied from a downloads folder, so the logic that shipped was not the logic that was committed and the build worked on exactly one machine. Two verifiers exist because PowerShell is the only thing guaranteed present on the target server, while the Linux builder should not need pwsh. tests/test_bundle_lock.py runs both against the same fixtures and fails if they disagree.
7.7 KiB
7.7 KiB