Bescherm de Windows-keten tegen MSYS-padvertaling #1598

Merged
brenno merged 6 commits from fix/windows-installer-msys into main 2026-08-20 03:11:15 +00:00
Owner

Reparatie van wat proeftag v0.4.7-rc1 blootlegde (#1583). Die tag hing 1 uur 52 minuten op Inno Setup installeren en is handmatig afgebroken. Het log toonde twee regels goed werk — de gepinde download en innosetup-7.1.0-x64.exe: OK — en daarna stilte, met bij het opruimen twee wees-processen: de installer en zijn .tmp-kind. Dat kind is de fase waarin Inno Setup zijn GUI heeft geopend.

Oorzaak

MSYS-padvertaling. Git Bash vertaalt élk argument dat met / begint naar een Windows-pad voordat een natief programma het ziet: /VERYSILENT kwam aan als C:/Program Files/Git/VERYSILENT. Geen stille-modusvlag → venster → wachten op een klik die op een runner nooit komt.

Drie plekken, waarvan twee nog nooit gedraaid

Plek Reparatie
Installatiestap (spiegel-workflow) shell: pwsh + Start-Process -Wait
ISCC "/DAppVersion=…" (packager) msys_safe (MSYS_NO_PATHCONV + MSYS2_ARG_CONV_EXCL, per aanroep)
signtool /sha1 /fd /tr … (packager) msys_safe

De -Wait dekt een tweede val: Inno's setup.exe keert terug zodra zijn .tmp-kind draait, dus zonder wachten kan ISCC aangeroepen worden vóórdat de installatie af is — een race die zich soms als "ISCC bestaat niet" zou tonen.

De signtool-route is de verraderlijkste van de drie: die is nooit gedraaid omdat er geen certificaat is. Zonder rc1 was die fout pas opgedoken op de dag dat het certificaat er wél was, en had hij eruitgezien als een certificaatprobleem.

Waarom de rooktoets dit niet ving

Die draaide op macOS met een nagemaakte iscc en signtool — vijf paden groen. MSYS-padvertaling bestaat daar niet. Precies daarvoor was de rc; de poort bewaakt daarom nu de vorm: pwsh + -Wait op de installatiestap, msys_safe om beide natieve aanroepen, en een hashvergelijking die een afwijking echt laat vallen (niet slechts afdrukt).

Toetsen

  • make check groen: 9.9xx tests, dekking 87,3%, per-bestand-vloer 0.
  • Poort gegroeid van 23 naar 25 controles; zes mutaties, zes betrapt — ISCC zonder schild, signtool zonder schild, helper weg, stap terug naar bash, -Wait weg, hashvergelijking uitgezet.
  • Er loopt daarnaast een bredere jacht op de rc1-klasse (fouten die alleen op Windows/CI opduiken) over alle vijf oppervlakken van de keten; bevestigde bevindingen landen als vervolgcommit op deze tak vóór de merge, of als apart issue.

Vervolg

Na de merge gaat v0.4.7-rc2 naar de spiegel (alleen daarheen, zoals rc1) om de installerbouw nu echt te zien draaien.

Reparatie van wat proeftag `v0.4.7-rc1` blootlegde (#1583). Die tag hing 1 uur 52 minuten op *Inno Setup installeren* en is handmatig afgebroken. Het log toonde twee regels goed werk — de gepinde download en `innosetup-7.1.0-x64.exe: OK` — en daarna stilte, met bij het opruimen twee wees-processen: de installer en zijn `.tmp`-kind. Dat kind is de fase waarin Inno Setup zijn GUI heeft geopend. ## Oorzaak MSYS-padvertaling. Git Bash vertaalt élk argument dat met `/` begint naar een Windows-pad voordat een natief programma het ziet: `/VERYSILENT` kwam aan als `C:/Program Files/Git/VERYSILENT`. Geen stille-modusvlag → venster → wachten op een klik die op een runner nooit komt. ## Drie plekken, waarvan twee nog nooit gedraaid | Plek | Reparatie | | --- | --- | | Installatiestap (spiegel-workflow) | `shell: pwsh` + `Start-Process -Wait` | | `ISCC "/DAppVersion=…"` (packager) | `msys_safe` (MSYS_NO_PATHCONV + MSYS2_ARG_CONV_EXCL, per aanroep) | | `signtool /sha1 /fd /tr …` (packager) | `msys_safe` | De `-Wait` dekt een tweede val: Inno's `setup.exe` keert terug zodra zijn `.tmp`-kind draait, dus zonder wachten kan ISCC aangeroepen worden vóórdat de installatie af is — een race die zich soms als "ISCC bestaat niet" zou tonen. De signtool-route is de verraderlijkste van de drie: die is nooit gedraaid omdat er geen certificaat is. Zonder rc1 was die fout pas opgedoken op de dag dat het certificaat er wél was, en had hij eruitgezien als een certificaatprobleem. ## Waarom de rooktoets dit niet ving Die draaide op macOS met een nagemaakte `iscc` en `signtool` — vijf paden groen. MSYS-padvertaling bestaat daar niet. Precies daarvoor was de rc; de poort bewaakt daarom nu de **vorm**: `pwsh` + `-Wait` op de installatiestap, `msys_safe` om beide natieve aanroepen, en een hashvergelijking die een afwijking echt laat vallen (niet slechts afdrukt). ## Toetsen - `make check` groen: 9.9xx tests, dekking 87,3%, per-bestand-vloer 0. - Poort gegroeid van 23 naar 25 controles; **zes mutaties, zes betrapt** — ISCC zonder schild, signtool zonder schild, helper weg, stap terug naar bash, `-Wait` weg, hashvergelijking uitgezet. - Er loopt daarnaast een bredere jacht op de rc1-klasse (fouten die alleen op Windows/CI opduiken) over alle vijf oppervlakken van de keten; bevestigde bevindingen landen als vervolgcommit op deze tak vóór de merge, of als apart issue. ## Vervolg Na de merge gaat `v0.4.7-rc2` naar de spiegel (alleen daarheen, zoals rc1) om de installerbouw nu echt te zien draaien.
fix(release): bescherm de Windows-keten tegen MSYS-padvertaling
All checks were successful
scans / scans (pull_request) Successful in 2m54s
static-gate / static-gate (pull_request) Successful in 5m47s
c0fced08e0
De proeftag v0.4.7-rc1 hing 1 uur 52 minuten op de stap "Inno Setup
installeren" en moest handmatig worden afgebroken. Het log liet precies twee
regels werk zien — download en sha256-verificatie, allebei goed — gevolgd door
stilte en twee wees-processen: innosetup-7.1.0-x64.exe en zijn .tmp-kind.

De oorzaak zit niet in Inno Setup maar in de shell eromheen. Git Bash draait op
MSYS, en die laag vertaalt élk argument dat met "/" begint naar een Windows-pad
voordat een natief programma het ziet. "/VERYSILENT" kwam aan als
"C:/Program Files/Git/VERYSILENT"; zonder herkende stille-modusvlag opende de
installer zijn venster en wachtte op een klik die op een runner nooit komt.

Drie plekken droegen dezelfde kwaal, waarvan er twee nog nooit gedraaid hadden:

* De installatiestap zelf → nu PowerShell, met Start-Process -Wait. Dat -Wait
  dekt meteen een tweede val: Inno's setup.exe keert terug zodra zijn
  .tmp-kind draait, dus zonder wachten kan ISCC aangeroepen worden vóórdat de
  installatie klaar is — een race die zich "soms" als "ISCC bestaat niet" zou
  tonen.
* ISCC "/DAppVersion=…" in de packager → door msys_safe (MSYS_NO_PATHCONV +
  MSYS2_ARG_CONV_EXCL), per aanroep en niet globaal, zodat bedoelde paden
  vertaald blijven.
* De volledige signtool-aanroep → idem. Deze route is nooit gedraaid omdat er
  geen certificaat is; zonder rc1 was deze fout pas opgedoken op de dag dat
  het certificaat er wél was, en had hij eruitgezien als een certificaatprobleem.

Waarom de rooktoets dit niet ving: die draaide op macOS met een nagemaakte
iscc en signtool, en MSYS-padvertaling bestaat daar niet. De poort bewaakt
daarom nu de vorm — pwsh + -Wait op de installatiestap, msys_safe om beide
natieve aanroepen, en de hashvergelijking die een afwijking echt laat vallen.
Zes mutaties, zes betrapt.

Verwijst naar #1583.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
De conclusie van een óúdere run op dezelfde tag kon een verse hertrigger binnen
seconden doden — precies het herstelpad na rc1: op de tag stond een cancelled
run, de hertrigger dispatcht, en leest ~11 s later die oude conclusie als 'de
build faalde', met de URL van de vórige poging als dwaalspoor. run_status
draagt nu created_at mee en een conclusie van vóór het T0-anker geldt als
verouderd (eenmalig herdispatchen) in plaats van als doodvonnis.

Daarnaast: --connect-timeout/--max-time op elke curl (de 45-minutenlus telt
pogingen, geen tijd — één geblackholede route hing hem anders urenlang op) en
timeout-minutes: 75 als harde buitenmuur.

Dubbel adversarieel bevestigde bevinding uit de ketenjacht na rc1 (#1583).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Vier verhardingen uit de ketenjacht na rc1: timeout-minutes 90 (rc1 bewees dat
een hang anders de zes-uur-standaard opmaakt), een concurrency-groep met
wachtrij i.p.v. cancel (een geannuleerde run laat op de tag precies de
conclusie achter die windows-ophalen als vals doodvonnis kon lezen), een
tag-wacht op workflow_dispatch (op main gedraaid zou elke stap zijn naam uit
'main' afleiden en een neprelease publiceren), en -PassThru + exitcode-controle
op de stille Inno-installatie — Start-Process werpt zelf niets bij een niet-nul
kind, en juist /SUPPRESSMSGBOXES onderdrukt de foutvensters.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ValueType none maakt volgens de Inno-handleiding alleen de sléútel aan en
negeert ValueName/ValueData. De belofte 'OciDeck onder Openen met… voor .md'
werd dus nooit in het register geschreven — de Verkenner leest waardenámen
onder OpenWithProgids. Nu een lege REG_SZ met de ProgID als naam, het
gedocumenteerde patroon (de .reg schrijft het REG_NONE-equivalent).

Ook: ChangesAssociations=yes, anders hoort de Verkenner pas bij een nieuwe
aanmelding van de associaties; en BundleDir overschrijfbaar via /DBundleDir,
zodat de map die de packager bewaakt en tekent aantoonbaar de map is die
ingepakt wordt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Vier gebreken die stil lagen omdat de route nog nooit draaide. De
signtool-keuze pakte met sort -Vr juist de óúdste: het versieloze legacy-pad
(bin/x64/) sorteert vóór de geversioneerde paden ('x' > '1'). Alles gaat nu in
één signtool-aanroep — een hardwaretoken vraagt zijn PIN per áánroep, en
twintig tijdstempelverzoeken in een salvo knijpt DigiCert per IP af — met drie
herhaalpogingen voor de tijdstempel-hik die dan nog overblijft. data/app.so
(de AOT-gecompileerde Dart-code: een PE-binary ondanks de extensie) en
hoofdletter-DLL's tekenen mee. En de compiler krijgt het bewaakte bundelpad
expliciet (/DBundleDir), dus een override wijzigt wat ingepakt wordt en niet
alleen wat gecontroleerd werd.

Rooktoetsen: batch (14 argumenten, één aanroep), hik-herstel (2 mislukkingen →
slagen), blijvende storing (exit 1), en zonder certificaat ongewijzigd gedrag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
test(windows): de poort dekt de rc1-klasse breder, en twee eigen zwaktes
All checks were successful
scans / scans (pull_request) Successful in 2m0s
static-gate / static-gate (pull_request) Successful in 4m37s
346d91c553
De jacht wees ook op de poort zelf. Het volgorde-anker matchte het éérste
voorkomen van de scriptnaam — een commentaarregel — dus één zin commentaar
verplaatsen maakte hem blind; hij ankert nu op de echte aanroepregel. En de
stille-modusvlaggen zelf waren ongepind: pwsh + -Wait hielp niets als iemand
/VERYSILENT uit de ArgumentList haalt.

Nieuw gepind: de vlaggen, -PassThru mét de vergelijking 'ExitCode -ne 0' (de
throw-boodschap bevat óók het woord ExitCode, dus het woord alleen was te
zwak — de mutatietoets betrapte dat), timeout/concurrency/tag-wacht op de
spiegel, het T0-anker en --max-time op de forge, en de twee .iss-reparaties.
Acht mutaties, acht betrapt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Author
Owner

Vijf commits erbij sinds de openingstekst: na de MSYS-reparatie is de hele keten adversarieel doorzocht op de rc1-klasse (fouten die alleen op Windows/CI opduiken). Eén bevinding is dubbel bevestigd, de rest aan de bron geverifieerd vóór reparatie.

Forge (531768f7)windows-ophalen kon de conclusie van een óúdere run op dezelfde tag lezen en een verse hertrigger binnen seconden doden; precies het herstelpad na rc1, met de URL van de vórige poging als dwaalspoor. Nu geankerd op created_at tegen een T0; een oude conclusie betekent eenmalig herdispatchen in plaats van exit 1. Plus curl-tijdslimieten en timeout-minutes: 75.

Spiegel (40455f8b)timeout-minutes: 90; concurrency-groep met wachtrij (géén cancel: een geannuleerde run laat op de tag precies de conclusie achter die hierboven het dwaalspoor was); tag-wacht op workflow_dispatch; en -PassThru + ExitCode -ne 0 op de stille installatie, want /SUPPRESSMSGBOXES onderdrukt juist de foutvensters.

.iss (74c663f3) — de belangrijkste stille: ValueType: none schrijft volgens de Inno-handleiding géén waarde, dus de beloofde "Openen met…"-vermelding voor .md heeft nooit bestaan. Nu een lege REG_SZ met de ProgID als naam. Plus ChangesAssociations=yes en een overschrijfbare BundleDir.

Packager (be620364) — de signeerroute (nooit gedraaid, geen certificaat) droeg vier gebreken die anders op signeerdag waren opgedoken: sort -Vr koos juist de óúdste signtool, twintig losse aanroepen betekenden twintig PIN-prompts en een tijdstempel-salvo dat DigiCert afknijpt, data/app.so en hoofdletter-DLL's tekenden niet mee. Nu één batchaanroep met herhaalpoging; rookgetoetst in beide richtingen.

Poort (346d91c5) — de jacht wees ook twee zwaktes in de poort zelf aan: het volgorde-anker matchte een commentaarregel, en de stille-modusvlaggen waren ongepind. Poort nu 28 controles; acht nieuwe mutaties, acht betrapt — waaronder één die mijn eigen te zwakke ExitCode-assertie betrapte.

Bewust doorgeschoven, met redenen: #1600 (uninstaller-ondertekening op signeerdag, LicenseFile-cosmetiek, het .reg-padcontrast, en een voorbestaand verwijder-vóór-upload-punt in publiceren).

Vijf commits erbij sinds de openingstekst: na de MSYS-reparatie is de hele keten adversarieel doorzocht op de rc1-klasse (fouten die alleen op Windows/CI opduiken). Eén bevinding is dubbel bevestigd, de rest aan de bron geverifieerd vóór reparatie. **Forge (`531768f7`)** — `windows-ophalen` kon de conclusie van een óúdere run op dezelfde tag lezen en een verse hertrigger binnen seconden doden; precies het herstelpad na rc1, met de URL van de vórige poging als dwaalspoor. Nu geankerd op `created_at` tegen een T0; een oude conclusie betekent eenmalig herdispatchen in plaats van `exit 1`. Plus curl-tijdslimieten en `timeout-minutes: 75`. **Spiegel (`40455f8b`)** — `timeout-minutes: 90`; concurrency-groep met wachtrij (géén cancel: een geannuleerde run laat op de tag precies de conclusie achter die hierboven het dwaalspoor was); tag-wacht op `workflow_dispatch`; en `-PassThru` + `ExitCode -ne 0` op de stille installatie, want `/SUPPRESSMSGBOXES` onderdrukt juist de foutvensters. **`.iss` (`74c663f3`)** — de belangrijkste stille: `ValueType: none` schrijft volgens de Inno-handleiding géén waarde, dus de beloofde "Openen met…"-vermelding voor `.md` heeft nooit bestaan. Nu een lege REG_SZ met de ProgID als naam. Plus `ChangesAssociations=yes` en een overschrijfbare `BundleDir`. **Packager (`be620364`)** — de signeerroute (nooit gedraaid, geen certificaat) droeg vier gebreken die anders op signeerdag waren opgedoken: `sort -Vr` koos juist de óúdste signtool, twintig losse aanroepen betekenden twintig PIN-prompts en een tijdstempel-salvo dat DigiCert afknijpt, `data/app.so` en hoofdletter-DLL's tekenden niet mee. Nu één batchaanroep met herhaalpoging; rookgetoetst in beide richtingen. **Poort (`346d91c5`)** — de jacht wees ook twee zwaktes in de poort zelf aan: het volgorde-anker matchte een commentaarregel, en de stille-modusvlaggen waren ongepind. Poort nu 28 controles; acht nieuwe mutaties, acht betrapt — waaronder één die mijn eigen te zwakke `ExitCode`-assertie betrapte. Bewust doorgeschoven, met redenen: #1600 (uninstaller-ondertekening op signeerdag, LicenseFile-cosmetiek, het .reg-padcontrast, en een voorbestaand verwijder-vóór-upload-punt in `publiceren`).
brenno merged commit e8e797af0e into main 2026-08-20 03:11:15 +00:00
Sign in to join this conversation.
No description provided.