# ALCOMD3 updater signing

Languages: English | [日本語](ALCOMD3_UPDATER.ja.md) | [简体中文](ALCOMD3_UPDATER.zh-CN.md)

This document covers updater key material and signature verification. For the
complete release workflow, use [RELEASE.md](./RELEASE.md).

ALCOMD3 uses its own updater key pair and `xtask` signing commands. Use the
ALCOMD3 updater key and `ALCOMD3_UPDATER_*` environment variable names for
ALCOMD3 releases.

### Key model

- The updater public key is embedded in `vrc-get-gui/src/updater.rs` as
  `static PUBLIC_KEY`.
- The private key is loaded by `xtask sign-alcom-updater` from:
  - `ALCOMD3_UPDATER_PRIVATE_KEY`
  - `ALCOMD3_UPDATER_PRIVATE_KEY_PASSWORD`
- The updater verifies the plain Windows setup executable
  `alcomd3-{version}-setup.exe`.
- The `.zip` artifact is for browser-download compatibility and is not used by
  the updater.

The updater JSON must contain the artifact URL and literal signature content,
not a signature file URL.

### Generate a key pair

Generate a key pair only when bootstrapping or intentionally rotating the updater key:

```powershell
$bytes = [byte[]]::new(32)
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$rng.GetBytes($bytes)
$rng.Dispose()
$env:ALCOMD3_UPDATER_PRIVATE_KEY_PASSWORD = [Convert]::ToBase64String($bytes)
cargo xtask generate-alcom-updater-key
```

Generated files are written under `artifacts/alcomd3-updater-key/`:

- `public-key-base64.txt`: copy this value into `vrc-get-gui/src/updater.rs`.
- `private-key.env`: portable environment file for signing.
- `private-key.ps1`: PowerShell environment file for signing.

The private key files are ignored and must not be committed. Back them up in a
secure location. If the private key is lost, builds using the embedded public
key cannot auto-update to future versions.

### Load signing variables

`cargo xtask release-build` automatically loads
`artifacts/alcomd3-updater-key/` when signing variables are not already set. It
prefers `private-key.ps1` and falls back to `private-key.env`.

PowerShell:

```powershell
. .\artifacts\alcomd3-updater-key\private-key.ps1
```

Portable `.env` loader:

```powershell
Get-Content .\artifacts\alcomd3-updater-key\private-key.env | ForEach-Object {
    $name, $value = $_ -split '=', 2
    [Environment]::SetEnvironmentVariable($name, $value, 'Process')
}
```

### Sign an installer

```powershell
$Version = "2.0.0"
$SetupDir = "target\x86_64-pc-windows-msvc\release\bundle\setup"
$Installer = "$SetupDir\alcomd3-$Version-setup.exe"
cargo xtask sign-alcom-updater $Installer
```

This writes:

```text
target/x86_64-pc-windows-msvc/release/bundle/setup/alcomd3-{version}-setup.exe.sig
```

The updater JSON generator reads the `.sig` file and inserts its content into
the `signature` field.

### Verify updater JSON

Always verify the final updater JSON before publishing the website:

```powershell
$Version = "2.0.0"
$SetupDir = "target\x86_64-pc-windows-msvc\release\bundle\setup"
cargo xtask verify-alcom-updater-json `
    --installer "$SetupDir\alcomd3-$Version-setup.exe" `
    --json website\public\api\gui\tauri-updater.json
```

For beta releases, verify `tauri-updater-beta.json` instead.

Verification checks that the JSON parses, `platforms.windows-x86_64` exists,
the signature is present, the URL matches the installer file name, and the
signature verifies with the public key embedded in `vrc-get-gui/src/updater.rs`.

### Key rotation rule

Do not rotate the updater key inside a normal release. If rotation is
unavoidable, publish a bridge release signed by the old key and containing the
new embedded public key before signing future installers with the new private key.
