# 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-<version>.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.
