# Releasing TeamsISO The release workflow at `.forgejo/workflows/release.yml` runs on **annotated tag pushes matching `v*.*.*`**. It builds, tests, publishes, packages an MSI, and uploads the MSI as a release asset. ## Prerequisites - A **Windows runner** registered to this Forgejo instance. WiX MSI builds require Windows; the existing CI runs on Linux for unit tests, but releases need a separate Windows runner. Register one with `forgejo-runner register` against a Windows host that has the .NET 8 SDK + WiX SDK access (the WiX SDK pulls itself via NuGet at build time, so no separate install). - The repository's **Create release on tag push** setting on (default), or skip it — the workflow will create the release if one doesn't exist. ## Cutting a release ```sh # Bump the version in Directory.Build.props if you haven't already. git tag -a v1.0.0 -m "TeamsISO 1.0.0" git push origin v1.0.0 ``` The workflow will: 1. Restore + build `TeamsISO.Windows.slnf` in Release with the tag's version. 2. Run unit tests (the `requires=ndi` integration tier is skipped — it needs a real NDI runtime which a CI runner won't have). 3. Publish `TeamsISO.App` and `TeamsISO.Console` for `win-x64`, framework-dependent (.NET 8 Desktop runtime is the user's responsibility). 4. Build `installer/TeamsISO.Installer.wixproj`, producing `TeamsISO-Setup-.msi`. 5. Upload the MSI as a workflow artifact (downloadable from the run page). 6. Attach the MSI to the GitHub-style Release for the tag, creating the release first if it doesn't exist. Pre-release flag is set automatically when the tag contains `-alpha`, `-beta`, or `-rc`. ## Code signing The release workflow has optional signtool integration. It runs only when the signing-cert secrets are configured on the repository — without them, builds remain unsigned and produce a SmartScreen warning on first launch. ### Enabling signing Set these secrets on `forge.wilddragon.net/zgaetano/teamsiso` → Settings → Actions → Secrets: | Secret | Required | Notes | | --- | --- | --- | | `SIGN_CERT_PFX_BASE64` | yes | Base64 of your code-signing PFX file. Generate with `certutil -encode in.pfx out.b64`, then strip the `-----BEGIN/END CERTIFICATE-----` lines. | | `SIGN_CERT_PASSWORD` | yes | The PFX password. | | `SIGN_TIMESTAMP_URL` | no | RFC 3161 timestamp server. Defaults to `http://timestamp.digicert.com`. | When all three are present, the workflow: 1. Decodes the PFX to a temp file on the runner before building. 2. Signs `publish/TeamsISO/TeamsISO.exe` after publish, before MSI build, so the binary embedded in the MSI is signed too. 3. Signs the produced MSI itself after WiX builds it. 4. Wipes the temp PFX from disk. Both signing steps use SHA-256 for both the file hash and the timestamp digest, which is what current Microsoft / SmartScreen guidance requires. ### Cert types - **OV (Organization Validation, ~$200/yr).** SmartScreen reputation is built per-publisher over time; brand-new OV certs still trip the warning until enough downloads accumulate. - **EV (Extended Validation, ~$300/yr, hardware token).** SmartScreen-trusted immediately. Token-based — to use one in CI you'll need to either (a) keep the runner on a host with the token plugged in, or (b) move to a cloud signing service like Azure Trusted Signing or DigiCert KeyLocker. For v1.0 we recommend the Azure Trusted Signing route: replace the PFX block in `release.yml` with `azure/trusted-signing-action` once an Azure subscription is set up. The current PFX path is the simplest thing that works for now.