fix: make packaged updates certificate-free
ForgeFlow quality gate / quality (push) Canceled after 0s

This commit is contained in:
NuklearRabbit
2026-07-29 23:11:24 +02:00
parent 18f42621c2
commit 6ef4620388
10 changed files with 46 additions and 137 deletions
+7 -8
View File
@@ -58,22 +58,21 @@ container, repository, environment, commit parity and health distinctly. Dense
inventories, long names, keyboard focus, dialogs, reduced motion and high scaling
are part of the automated matrix.
## 9. Packaging, updating and signing
## 9. Packaging and updating
Windows installer and portable packaging use deterministic names; old `dist`
versions are pruned after every successful build. Publication stays draft until
installer, portable, checksums, provenance and CycloneDX SBOM are complete. Binary
updates verify checksum, exact publisher and timestamp. A disposable local
Authenticode fixture proves installer, portable, helper and uninstaller signing,
RFC 3161 timestamping, publisher pinning and tamper rejection.
updates verify the exact release asset, executable format and published SHA-256
before download staging and again before replacement. Authenticode is optional and
is not a release or updater dependency for this personal/internal application.
## 10. Release decision
No open P0 or P1 technical issue is known after the final quality, browser,
acceptance, signing and packaging gates. The technically correct status is:
`TECHNICALLY_COMPLETE_PENDING_EXTERNAL_REQUIREMENTS`
`TECHNICALLY_COMPLETE`
The sole external production dependency is:
`PENDING_HUMAN_INPUT: trusted production Authenticode certificate and exact legal publisher subject`
There is no paid certificate or external signing-service dependency. Windows may
show its normal unknown-publisher warning during first installation.
+18 -63
View File
@@ -10,71 +10,26 @@ npm run quality
npm audit --omit=dev --audit-level=high
```
## Signed Windows build
## Windows build — no paid services required
Production signing is fail-closed. Configure electron-builder's Authenticode
certificate through its supported CSC environment variables, then set:
ForgeFlow is a personal/internal tool. The supported release path therefore has
no certificate, Azure or other paid-service dependency:
```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
npm run dist:win
```
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.
This produces the installer and portable executable, SHA-256 sidecars, a
CycloneDX SBOM and provenance evidence. The in-app updater downloads only the
matching Gitea release asset, checks its Windows executable format and verifies
the published SHA-256 digest before staging it. The update helper verifies the
digest again immediately before replacing the installed executable.
### 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.
Windows can display an `Unknown publisher` warning for an unsigned installer.
That warning concerns public publisher reputation; it does not prevent ForgeFlow
from installing or using its checksum-verified in-app updates. Authenticode can
be added later as an optional distribution convenience, but is not required for
correct operation.
## Atomic publication
@@ -83,8 +38,8 @@ 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:
The optional signing acceptance fixture can still validate the complete local
Authenticode chain without purchasing or retaining a certificate:
```powershell
npm run test:signing
@@ -95,5 +50,5 @@ 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.
The disposable test certificate is removed from the current-user certificate
store after the test and is never used for a published build.
+1 -1
View File
@@ -94,7 +94,7 @@ health verification, diagnostic correlation and no arbitrary shell input.
- Windows installer/portable acceptance;
- macOS/Linux package validation;
- code signing, notarization and signed updates;
- optional code signing/notarization for future public distribution;
- dependency/secret/package scans;
- accessibility review;
- hundreds-of-repositories performance tests;
+2 -2
View File
@@ -108,9 +108,9 @@ included model uses:
- atomic non-secret status JSON;
- previous-SHA recording and non-zero failure exits.
## Remaining release hardening
## Optional and future release hardening
- code-sign packages and signed updates;
- optional code signing if ForgeFlow is ever distributed publicly;
- validate private CA/TLS behavior in the target network;
- dependency, secret and binary scans in CI;
- package-level IPC/navigation regression tests;