A user found this in their log and had never been offered a choice:
WARN GameStream/Moonlight compat ENABLED (--gamestream): its pairing runs over
plain HTTP and its legacy control encryption can reuse GCM nonces
(security-review #5/#9) — an on-path LAN attacker could MITM pairing or
recover input. Enable only on a TRUSTED network.
They were right. The `gamestream` task carried no `Flags: unchecked`, so it was
pre-ticked; and since a silent install takes the wizard's own task defaults
(1839d756), a winget install turned it on with no checkbox ever shown. The host
warns that this plane is a security downgrade on every single start, so having
the installer enable it by default cannot be squared with our own advice — least
of all on the path where nobody sees a wizard.
Now unchecked, matching `allowpublicfw`, the other task with a security
consequence. A default install therefore lands `PUNKTFUNK_HOST_CMD=serve`, the
native-only host; Punktfunk's own clients are unaffected, since the native
punktfunk/1 plane is always on. Unattended opt-in is `/MERGETASKS=gamestream`.
Scope, deliberately: this changes FRESH installs only. `GamestreamParam` already
omits the flag entirely unless `FreshHostInstall`, so no existing host has its
choice touched by an upgrade, and anyone relying on Moonlight today keeps it.
`DEFAULT_HOST_CMD` (the service's fallback when host.env carries no
PUNKTFUNK_HOST_CMD line at all) is deliberately NOT flipped here: the installer
always writes the line explicitly, so it does not affect a normal install, and
inverting it would silently disable Moonlight for anyone whose host.env lost that
line — a runtime regression that belongs in its own change, if at all.
Docs corrected everywhere they stated the old default, since three of them now
told users the opposite of what ships: the winget Agreement shown BEFORE install
(it said "enabled by default" and gave the opt-OUT override), the Windows
packaging README, and host.env.example. The `--override` example in the installer
manifest is inverted with it (`/MERGETASKS=gamestream` to add, `!` to remove).
Verified: [Tasks] + [Code] compile with ISCC 6.7.1 on the windows-amd64 runner
(all optional features defined), and the winget catalogue rebuilds and passes
29/29 with the edited manifests.
winget manifests — Windows host
The reviewed source of truth for the unom.PunktfunkHost winget package. Everything except
PackageVersion / InstallerUrl / InstallerSha256 / ReleaseNotesUrl is edited here;
scripts/ci/winget-manifest.ps1 only substitutes those four per release, so the switches,
agreements and installation notes stay under normal code review.
| File | Purpose |
|---|---|
unom.PunktfunkHost.yaml |
Version manifest — ties the other two together. |
unom.PunktfunkHost.installer.yaml |
Installer type, scope, silent switches, ProductCode, URL + hash. |
unom.PunktfunkHost.locale.en-US.yaml |
User-facing metadata, Agreements, InstallationNotes. |
Why these choices
InstallerType: inno,Scope: machine,ElevationRequirement: elevatesSelf. The host registers a SYSTEM service, installs drivers and opens firewall ports;PrivilegesRequired=adminin the.issmeans Setup raises its own UAC prompt. There is no per-user scope.ProductCode: {7C9E6A52-…}_is1— Inno's ARP key is<AppId>_is1. This is what correlates an installed host with the package forwinget list/winget upgrade. It must trackAppIdinpackaging/windows/punktfunk-host.iss— if that GUID ever changes, change it here too or upgrades silently stop being detected.interactiveis inInstallModes.winget install unom.PunktfunkHost --interactiveruns the full existing wizard: every task checkbox, the web-console password page, the VB-CABLE notice. Nothing about the installer changes to support it.- No
/MERGETASKSin the silent switches. A silent install deliberately takes the same task defaults the wizard shows, so the product does not differ by install channel — a per-channel default is a support trap ("it works when I install it by hand"). The disclosures the wizard puts on screen are carried byAgreementsinstead, which winget shows before install and requires the user to accept. UpgradeBehavior: install— Inno upgrades in place (UsePreviousAppDir=yes). Uninstalling first would run the[UninstallRun]service + driver teardown between versions.
Opting out of individual tasks
Inno's /MERGETASKS takes ! prefixes to deselect a default-checked task. Use --override
(replaces winget's switches) rather than --custom (appends — you would end up with two
/MERGETASKS on one command line):
winget install unom.PunktfunkHost --override "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /MERGETASKS=!gamestream"
Task names: installdriver, installgamepad, installaudiocable, installhdrlayer,
gamestream, allowpublicfw, startservice, trayicon.
Two installer behaviours that exist for this path
Both are in packaging/windows/punktfunk-host.iss and both also fix pre-existing bugs on the
plain double-click upgrade path:
InitializeSetupusesSuppressibleMsgBox, notMsgBox. A plainMsgBoxignores/SUPPRESSMSGBOXESand displays even under/VERYSILENT— an unattended install on a box that already runs Sunshine/Apollo would block on an invisible modal dialog. Suppressed it returnsIDNO, so that install aborts (Setup exits non-zero) rather than proceeding into the unsupported dual-host state.GamestreamParamis fresh-install-only. On an upgrade the flag is omitted entirely, whichservice installreads as "keep host.env as-is". Passing an explicit on/off would rewritePUNKTFUNK_HOST_CMDwhenever it still holds either canonical value — so a silent upgrade, where no wizard carries the old choice forward, would flip a user's GameStream setting with nothing on screen.PublicFwParamis fresh-install-only too, and--allow-public-networkis now tri-state (=on/=off/ absent → keep the recorded choice, resolved from thefw-allow-publicmarker inwindows/service.rs). This task is default-unchecked, so without the change a silent upgrade would have silently revoked a Public-network opt-in the user made once. The bare--allow-public-networkform still meansonfor existing scripts; a malformed value is a hard error rather than a fall-through, since a typo'd opt-out must never resolve to "keep Public open".
Release flow
.gitea/workflows/windows-host.yml runs on stable v* tags only, after the installer is
attached to the Gitea release — winget validates the URL and hash, so a manifest must never be
published ahead of its artifact:
scripts/ci/winget-manifest.ps1 -Version 0.19.2 `
-InstallerPath C:\t\out\punktfunk-host-setup-0.19.2.exe -OutDir C:\t\out\winget
The generated trio is attached to the same release. Canary builds are excluded: winget pins one
immutable artifact per version, so the rolling canary/ alias has nothing it could point at.
Validating a change
winget validate --manifest packaging\winget
winget install --manifest packaging\winget # local install from the manifest
For a throwaway check, winget-pkgs' Tools\SandboxTest.ps1 runs a manifest in Windows Sandbox.
Note the host needs a real GPU and installs drivers, so a Sandbox run exercises the manifest
(download, hash, switches, ARP correlation) rather than a working stream.
Publishing
Through our own REST source on unom-1 — see server/. It sits alongside the
docs (3220) and flatpak (3230) services, behind the same edge Caddy; windows-host.yml rebuilds and
ships its catalogue on every stable tag, so releasing is one pipeline with no manual step.
winget source add -n punktfunk https://winget.punktfunk.unom.io -t Microsoft.Rest # elevated, once
winget install unom.PunktfunkHost
These manifests stay in winget-pkgs' own format rather than a bespoke one, so submitting upstream
later is a copy, not a rewrite. Two things would need attention on that path: the signing note
below, and Agreements being verified-developers-only in the community repo.
Signing. The installer is currently signed with a self-signed cert (
CN=unom, subject == issuer) and ships a.cerusers import manually. winget does not sign anything; it downloads and runs the same binary, so SmartScreen behaves exactly as it does for a browser download. That is a pre-existing condition rather than something winget introduces — but the community repo (microsoft/winget-pkgs) gates on it via itsBinary-Validation-Error/Validation-Defender-Errorchecks, so a submission there needs a publicly-trusted cert (Azure Trusted Signing is the cheap path). A self-hosted source has no such gate.