forked from unom/punktfunk
Releases move from the self-signed CN=unom cert to Azure Artifact Signing (formerly Trusted Signing): account `unomsigning`, profile `unom-io`, signed by the `punktfunk-ci-signing` service principal, which holds only the Artifact Signing Certificate Profile Signer role scoped to that one profile. Both pack scripts gain the backend ahead of the existing .pfx and ephemeral fallbacks, so canary and fork builds are unaffected. Three things that are easy to get wrong, and are handled here rather than discovered in the field: Azure mints a leaf certificate per signing request that expires in about three days. Both scripts previously retried WITHOUT a timestamp when a timestamped sign failed — under Azure that ships an artifact which verifies on the runner and goes untrusted days later, on every user's machine at once. The retry is now gated on the mode: still lenient for a .pfx whose cert outlives the release, a hard failure for Azure. The MSIX manifest Publisher must equal the signer subject byte-for-byte, because package identity is Name + Publisher. The default is now the profile's verified subject, written with `[char]0xFC` escapes rather than literal umlauts so this UTF-8-without-BOM file cannot silently mojibake the DN into one that no longer matches. pack-msix.ps1 now also reads the signature back off the packed .msix and fails on drift — asymmetric on purpose: a subject that disagrees is fatal, a subject that cannot be read is only a warning, since Get-AuthenticodeSignature's .msix support varies by Windows version and signtool has already reported success by then. NOTE this changes package identity, so existing installs need an uninstall, not an upgrade. The updater's leaf-pinning note was wrong and is corrected: update/windows.rs claimed the AUTHENTICODE_SHA256 field made Trusted Signing "a manifest edit", but a per-request leaf is exactly what a leaf pin cannot track — a pin would go stale within days and reject every release after it. Drivers are deliberately untouched: their catalogs keep the DRIVER_CERT_* cert and the installer still plants it as a machine root. The two signatures were always independent (SmartScreen/UAC vs PnP), which is why the installer could move without them. Whether a publicly-trusted catalog would let us drop that root plant is recorded as an unverified follow-up, not assumed. Verified: both scripts parse under the PowerShell 7 AST parser, both workflows are valid YAML, the evaluated Publisher default matches the subject Azure reports for the profile (86 chars, ordinal), rustfmt clean. NOT verified on Windows — the sign path itself needs an on-glass run on .133.
117 lines
6.5 KiB
Markdown
117 lines
6.5 KiB
Markdown
# 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=admin`
|
|
in the `.iss` means 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 for `winget list` / `winget upgrade`. **It must track `AppId` in
|
|
`packaging/windows/punktfunk-host.iss`** — if that GUID ever changes, change it here too or
|
|
upgrades silently stop being detected.
|
|
- **`interactive` is in `InstallModes`.** `winget install unom.PunktfunkHost --interactive` runs the
|
|
full existing wizard: every task checkbox and the web-console password page.
|
|
Nothing about the installer changes to support it.
|
|
- **No `/MERGETASKS` in 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 by `Agreements` instead, 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):
|
|
|
|
```powershell
|
|
winget install unom.PunktfunkHost --override "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /MERGETASKS=!gamestream"
|
|
```
|
|
|
|
Task names: `installdriver`, `installgamepad`, `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:
|
|
|
|
- **`InitializeSetup` uses `SuppressibleMsgBox`, not `MsgBox`.** A plain `MsgBox` ignores
|
|
`/SUPPRESSMSGBOXES` and displays even under `/VERYSILENT` — an unattended install on a box that
|
|
already runs Sunshine/Apollo would block on an invisible modal dialog. Suppressed it returns
|
|
`IDNO`, so that install aborts (Setup exits non-zero) rather than proceeding into the unsupported
|
|
dual-host state.
|
|
- **`GamestreamParam` is fresh-install-only.** On an upgrade the flag is omitted entirely, which
|
|
`service install` reads as "keep host.env as-is". Passing an explicit on/off would rewrite
|
|
`PUNKTFUNK_HOST_CMD` whenever 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.
|
|
- **`PublicFwParam` is fresh-install-only too**, and `--allow-public-network` is now tri-state
|
|
(`=on` / `=off` / absent → keep the recorded choice, resolved from the `fw-allow-public` marker in
|
|
`windows/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-network` form still means `on` for 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:
|
|
|
|
```powershell
|
|
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
|
|
|
|
```powershell
|
|
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/`](server/README.md). 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.
|
|
|
|
```powershell
|
|
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 signed with **Azure Artifact Signing** (account `unomsigning`,
|
|
> profile `unom-io`) — a publicly trusted CA, so there is no `.cer` for users to import. This
|
|
> removed the blocker on submitting to the community repo (`microsoft/winget-pkgs`), whose
|
|
> `Binary-Validation-Error` / `Validation-Defender-Error` checks require a publicly trusted cert;
|
|
> the remaining upstream obstacle is `Agreements` being verified-developers-only. Note that a
|
|
> trusted cert is not an instant SmartScreen bypass: reputation still accrues per publisher over
|
|
> downloads, it just now accrues to a named identity instead of being permanently unknown.
|