Compress-Archive on Windows PowerShell writes the OS path separator into entry
names, so the archives came out with "tor\tor.exe". The ZIP format mandates
forward slashes, and 5.1.0 shipped "tor/tor.exe" from `zip -X` on Linux -- this
was a regression introduced when the packaging moved to the signing host.
It is not cosmetic for this application. Extractors that take the backslash
literally produce a file named "tor\tor.exe" in the archive root rather than a
tor directory, which puts the bundled Tor somewhere wowlet does not look. The
daemon is given an exclusive --tx-proxy, so a wallet that cannot find its Tor
cannot relay a transaction at all.
Archives are now built through System.IO.Compression with entry names
normalised explicitly, and the job asserts the result: a backslash in any entry
name, or a missing tor/tor.exe, fails the build rather than shipping.
Caught by extracting the artifact and diffing it against the 5.1.0 release
before publishing.
Linux: the x86_64 AppImage now builds on the Gitea runner. Unlike the Windows
lane, which builds a static toolchain of its own through contrib/depends, it
links against the host's Qt6 -- so those dependencies are owned by such-fleet
(roles/wowlet_build_host) and the job asserts them rather than apt-installing.
A workflow that installs needs sudo on a shared runner and makes the build
host's contents a property of whichever job ran last.
Windows: the lane now publishes two archives instead of one. Authenticode
mutates the exe, so a signed binary can never byte-match a build someone
reproduces from source. Shipping only the signed one quietly costs the project
its reproducibility story; shipping only the unsigned one costs every normal
user a SmartScreen warning. Both, with both hashes in the PGP-signed
hashes.txt, costs neither -- and keeps one canonical download page rather than
splitting the project across a fork.
The AppImage lane carries the packaging knowledge that a plain linuxdeploy run
does not: qmlimportscanner does not follow a module's own qmldir dependency
chain, so the QtQuick and QtQml trees are copied wholesale and each copied
plugin's Qt libraries resolved by hand, and a guard fails the build if
mining.qml ever imports QtQuick.Controls again rather than shipping a white
mining tab.
The first Gitea run built cleanly all the way through -- depends, wowlet.exe,
staging -- and then died on the last step:
::error::@actions/artifact v2.0.0+, upload-artifact@v4+ and
download-artifact@v4+ are not currently supported on GHES.
Gitea Actions implements the older artifact protocol, so the v4 actions (which
use @actions/artifact v2) refuse to talk to it. Hash Bags' Windows lane already
uses v3 for the same reason.
Pinned with a comment so nobody upgrades it back and loses a 22 minute build to
the same error.
Gitea is master and GitHub is a mirror, but the Windows and Linux jobs still
only existed in .github/workflows, so GitHub was doing real build work. This
moves Windows.
Two jobs on two machines, which is the point rather than an accident:
build runs on `deb` (windows-latest:host — it carries the MinGW
cross-compiler) and produces an unsigned wowlet.exe.
sign runs on desktop-iim2fs2 (windows:host), the machine with the EV
code-signing token physically in it.
The signing job does not itself sign. Its runner is NT SERVICE\act_runner,
which cannot use the token: SafeNet holds the login per user and the login is
established interactively by an operator. So the job queues the binary for the
Fleet-installed broker (roles/windows_code_signing) and waits. CI never holds
the key and never holds the token password, so it cannot spend one of the
token's three password attempts.
Differences from the GitHub lane, all because this is a real fleet host rather
than a disposable hosted runner:
- No apt install and no sudo. Every dependency is already present on deb, and a
first step asserts the toolchain — including that mingw is the posix
threading variant — and fails pointing at such-fleet rather than half
building.
- No disk-freeing or fallocated swap. Those existed to survive a hosted
runner's 16G/14G budget; deb has 30G and 3.1T free.
- depends builds at -j4 and wowlet at -j6 rather than -j2 for the same reason.
The exe is staged unzipped between the jobs because the broker signs one PE at
a time; the published zip is assembled after signing, so the archive contains
the signed binary. The signature, its RFC 3161 timestamp and the expected
signer are all re-verified on the artifact that actually ships.
Dispatch-only: both runners are capacity 1 and shared with other lanes.