100 lines
4.0 KiB
Markdown
100 lines
4.0 KiB
Markdown
# Releasing ForgeFlow
|
|
|
|
ForgeFlow releases are built only from a clean, reviewed commit on Node 22 LTS.
|
|
|
|
## Quality gate
|
|
|
|
```powershell
|
|
npm ci
|
|
npm run quality
|
|
npm audit --omit=dev --audit-level=high
|
|
```
|
|
|
|
## Signed Windows build
|
|
|
|
Production signing is fail-closed. Configure electron-builder's Authenticode
|
|
certificate through its supported CSC environment variables, then set:
|
|
|
|
```powershell
|
|
$env:FORGEFLOW_SIGNED_RELEASE = '1'
|
|
$env:FORGEFLOW_EXPECTED_PUBLISHER = 'CN=Exact Legal Publisher, O=Exact Legal Organization, C=BE'
|
|
npm run dist:win:signed
|
|
```
|
|
|
|
The signed command requires signed-release mode, an exact publisher subject and
|
|
either a classic `WIN_CSC_LINK` certificate configuration or complete Azure
|
|
credentials. It enables electron-builder's `forceCodeSigning` gate, so missing
|
|
signing material cannot silently produce a production candidate.
|
|
|
|
### Recommended: Azure Artifact Signing
|
|
|
|
1. Create an Azure Artifact Signing account and identity-validation certificate
|
|
profile for the legal ForgeFlow publisher.
|
|
2. Create an Entra app registration and give its service principal the
|
|
`Artifact Signing Certificate Profile Signer` role on that account.
|
|
3. Store the following as protected CI variables—never in Git:
|
|
|
|
```powershell
|
|
$env:AZURE_TENANT_ID = '<tenant id>'
|
|
$env:AZURE_CLIENT_ID = '<application/client id>'
|
|
$env:AZURE_CLIENT_SECRET = '<secret value>'
|
|
$env:FORGEFLOW_AZURE_SIGNING_ENDPOINT = 'https://<region>.codesigning.azure.net/'
|
|
$env:FORGEFLOW_AZURE_SIGNING_ACCOUNT = '<artifact signing account>'
|
|
$env:FORGEFLOW_AZURE_CERTIFICATE_PROFILE = '<certificate profile>'
|
|
$env:FORGEFLOW_SIGNED_RELEASE = '1'
|
|
$env:FORGEFLOW_EXPECTED_PUBLISHER = 'CN=<exact subject from Get-AuthenticodeSignature>'
|
|
npm run dist:win:signed
|
|
```
|
|
|
|
The generated configuration uses SHA-256 and Microsoft's RFC 3161 timestamp
|
|
service. `FORGEFLOW_EXPECTED_PUBLISHER` must still contain the complete subject
|
|
reported by the resulting certificate, even though Azure's builder option uses
|
|
its CN component.
|
|
|
|
### Alternative: classic CA certificate
|
|
|
|
When a CA supplies a CI-compatible PFX or hardware/cloud connector supported by
|
|
electron-builder, configure its protected values and use the same command:
|
|
|
|
```powershell
|
|
$env:WIN_CSC_LINK = 'C:\secure\forgeflow-signing.pfx'
|
|
$env:WIN_CSC_KEY_PASSWORD = '<secret password>'
|
|
$env:FORGEFLOW_SIGNED_RELEASE = '1'
|
|
$env:FORGEFLOW_EXPECTED_PUBLISHER = 'CN=<exact legal subject>, O=<organization>, C=BE'
|
|
npm run dist:win:signed
|
|
```
|
|
|
|
Do not purchase a certificate before the CA or cloud service confirms the exact
|
|
legal subject and that its key-storage method works with the intended Windows CI
|
|
runner. An ordinary OV certificate can still accumulate SmartScreen reputation;
|
|
EV or Azure Artifact Signing provides immediate publisher trust.
|
|
|
|
Both installer and portable executable must have a valid Authenticode signature,
|
|
the expected publisher and a timestamp. The build also creates SHA-256 files, a
|
|
CycloneDX SBOM and a provenance document containing commit and build ID.
|
|
|
|
Without `FORGEFLOW_SIGNED_RELEASE=1`, local builds may be unsigned for development
|
|
testing but must never be published as production releases.
|
|
|
|
## Atomic publication
|
|
|
|
`npm run release:binary` keeps the Gitea release in draft state while uploading
|
|
the installer, portable executable, two checksums, provenance and SBOM. It only
|
|
publishes after all six assets are present. A failed upload leaves a draft rather
|
|
than exposing an incomplete updater target.
|
|
|
|
The publisher check is an exact subject match, not a substring match. Before a
|
|
production certificate is available, validate the complete local chain with:
|
|
|
|
```powershell
|
|
npm run test:signing
|
|
```
|
|
|
|
This disposable fixture signs installer, portable, update-helper and uninstaller
|
|
stand-ins, requires an RFC 3161 timestamp, and proves rejection of a missing
|
|
timestamp, wrong publisher and a modified binary. Its certificate is removed
|
|
from the current-user certificate store after the test.
|
|
|
|
The production Authenticode certificate and exact legal publisher identity are
|
|
`PENDING_HUMAN_INPUT`; all surrounding build and verification code is complete.
|