Skip to content

release(native): establish platform code signing, notarization, artifact identity & rollback trust #574

Description

@qnbs

Context

WorldScript Studio's desktop release pipeline already has meaningful integrity controls, but it currently stops short of OS-native trust for downloaded installers.

Current release evidence and documentation distinguish these layers correctly:

Git commit/tag signature
        ≠
GitHub build provenance / attestation
        ≠
Tauri updater Minisign signature
        ≠
macOS Developer ID + notarization
        ≠
Windows Authenticode signature

The updater path already verifies per-platform Tauri updater artifacts with the configured Minisign public key. Current v1.28.x release evidence nevertheless states explicitly that platform code-signing and notarization remain separate claims. docs/TAURI-CI.md documents macOS APPLE_* requirements and says Windows Authenticode still requires a CA-issued certificate. docs/TAURI-UPDATER.md likewise documents the intended macOS/Windows signing inputs but the normal release pipeline does not yet make these guarantees authoritative.

The binding native roadmap also requires packaged identity, signing/update trust, rollback and installer evidence before native stable admission.

No current open issue owns this cross-platform release-trust remainder end to end.

Related but distinct:

Goal

Establish one explicit, testable native-release trust contract for supported desktop platforms:

SOURCE / TAG IDENTITY
        ↓
TRUSTED CI BUILD
        ↓
ARTIFACT IDENTITY + PROVENANCE
        ↓
OS-NATIVE SIGNATURE / NOTARIZATION WHERE APPLICABLE
        ↓
UPDATER SIGNATURE + MANIFEST CONSISTENCY
        ↓
INSTALL / UPDATE / ROLLBACK VERIFICATION

The objective is not simply to make Gatekeeper/SmartScreen warnings disappear. It is to make every release artifact's identity, signing authority, update relationship, revocation/rotation behavior and recovery path explicit.


1. Current release-trust inventory

Before changing CI, inventory every produced desktop artifact and its existing trust layer.

At minimum record for each current platform/artifact:

Linux:
  .deb
  .rpm
  .AppImage

Windows:
  .msi
  .exe / NSIS bundle where produced

macOS:
  .dmg
  .app.tar.gz updater payload

Cross-platform:
  latest.json
  updater .sig files
  GitHub provenance/attestations if/when present
  release checksums/digests if present

For every artifact capture:

Artifact Built by OS-native signature Updater signature Provenance Verification command Current gap

Do not call an installer "signed" solely because a different updater archive has a Minisign .sig file.


2. macOS Developer ID signing + notarization

Define and implement the production macOS release path using the current Apple-supported model.

Required properties:

  • Developer ID signing identity is explicit;
  • credentials exist only in the release job that needs them;
  • hardened-runtime/entitlement requirements are reviewed rather than copied blindly;
  • all executable code in the distributed app bundle is signed consistently;
  • notarization is submitted and reaches an accepted terminal result before publication is called successful;
  • notarization ticket is stapled where applicable;
  • the published .dmg and updater bundle are independently verified after packaging;
  • CI records non-sensitive verification evidence (codesign, spctl, notarization/stapling status) without dumping certificate/private material;
  • failure to sign/notarize a release that claims these guarantees is fail-closed.

A locally usable unsigned developer build may remain possible, but it must be visibly distinct from a production release artifact.

Credential policy

Inventory and minimize the currently documented APPLE_* secret surface.

Prefer modern short-lived/notarization credentials where upstream tooling supports them; if long-lived credentials remain necessary, document:

owner
scope
rotation procedure
revocation procedure
recovery procedure

Never expose Apple credentials to pull-request-controlled code.


3. Windows Authenticode signing

Define and implement an evidence-backed Windows signing path.

Required decisions/evidence:

  • certificate source/type appropriate to the project and distribution model;
  • secure CI access mechanism for the private signing key or signing service;
  • SHA-256 signing;
  • trusted timestamping so signatures remain valid after certificate expiry where the platform contract permits;
  • .msi and .exe/NSIS artifacts covered as applicable;
  • post-build signtool verify or equivalent verification against the published bytes;
  • subject/publisher identity documented truthfully;
  • renewal/rotation/revocation procedure;
  • no certificate/private-key material exposed to normal PR jobs.

SmartScreen reputation is not itself a cryptographic acceptance criterion. Document it as a distribution UX consideration rather than pretending code signing guarantees immediate reputation.


4. Linux artifact trust policy

Linux desktop distribution has no single universal Authenticode/Gatekeeper equivalent.

Define an explicit policy for the formats WorldScript publishes rather than making a vague "all installers signed" claim.

Evaluate, as applicable:

Do not introduce redundant signature layers with no documented verifier/user path.


5. Updater trust remains a separate layer

Preserve the current Tauri updater signature model as an independent control.

Explicitly prove:

latest.json identifies the intended release
        ↓
URL selects the intended artifact
        ↓
artifact bytes match the signature
        ↓
configured public key rejects modified/foreign payloads
        ↓
installation/relaunch occurs only after verification

Test both positive and negative cases.

Required negative cases include:

  • modified updater payload;
  • wrong signature;
  • wrong manifest signature/entry where applicable;
  • release manifest pointing at the wrong platform/architecture;
  • stale/older release offered unexpectedly;
  • missing asset;
  • interrupted download;
  • key mismatch after a planned rotation.

Do not conflate updater Minisign with macOS/Windows platform signatures in UI or docs.


6. Signing-key lifecycle and emergency response

Every signing authority must have a documented lifecycle.

For each key/certificate define:

PURPOSE
OWNER
STORAGE / CI ACCESS MODEL
ROTATION TRIGGER
EXPIRY
REVOCATION PROCEDURE
COMPROMISE RESPONSE
PUBLIC-KEY / CERTIFICATE UPDATE PROCEDURE
OLD-RELEASE VERIFICATION CONSEQUENCES

At minimum cover:

Updater-key rotation

A rotation must not strand already-installed clients.

Design the transition explicitly before replacing the embedded updater public key. If the updater architecture only trusts one key at a time, define the necessary bridge-release sequence and recovery behavior.

A compromised updater key is a security event, not an ordinary dependency bump.


7. Release artifact identity and manifest coherence

Create one release evidence manifest or equivalent machine-verifiable record tying together:

release tag
source commit SHA
workflow/run identity
application version
platform + architecture
artifact filename
artifact SHA-256
OS signing identity/status where applicable
updater signature presence/status
provenance/attestation reference

The exact serialization format is implementation-defined, but duplicate sources of truth should be avoided.

latest.json, GitHub Release assets and the actual uploaded bytes must be checked for exact agreement.

Do not generate hashes before a later signing/notarization step mutates the artifact.


8. Reproducibility and rebuild evidence

This issue does not require immediate bit-for-bit reproducible desktop binaries on every OS, but it must make the level of reproducibility explicit.

Inventory nondeterministic inputs:

Classify release reproducibility as one of:

SOURCE_REPRODUCIBLE
DEPENDENCY_GRAPH_REPRODUCIBLE
BUILD_ENVIRONMENT_PINNED
FUNCTIONALLY_REBUILDABLE
BIT_FOR_BIT_REPRODUCIBLE
NOT_YET_PROVEN

Do not claim deterministic/reproducible binaries without evidence.

Where bit-for-bit comparison is impossible due to signatures/timestamps, compare stable pre-signing payloads or normalized components only if this produces meaningful assurance.

#529 remains the provenance/SBOM owner; #570/#572/#573 own the underlying toolchain determinism.


9. Rollback / bad-release response

Define a safe response to a signed but defective release.

At minimum answer:

  • can latest.json be rolled back safely?;
  • does the updater permit downgrade, and should it?;
  • how are incompatible persisted-data/schema migrations handled?;
  • how is a bad artifact withdrawn without breaking already-installed clients?;
  • when is a replacement patch release required instead of manifest rollback?;
  • how do platform signatures/notarization behave for withdrawn releases?;
  • how are release notes/status pages/docs corrected?;

Data compatibility outranks release convenience. Never downgrade automatically across a persisted-data format boundary that the older version cannot safely read.

Coordinate project/schema compatibility with #553 and protected-data migration with #445.


10. CI trust boundary / least privilege

Release-signing jobs are privileged code-execution environments.

Required properties:

  • secrets are unavailable to ordinary pull-request jobs;
  • release workflow inputs are validated;
  • release only builds from admitted tags/refs according to policy;
  • actions remain SHA-pinned;
  • signing occurs only after required source/CI gates;
  • artifacts passed into a privileged signer have a trusted provenance/identity path;
  • no PR-controlled artifact can be substituted into the signing step;
  • environments/approvals are used where appropriate;
  • logs/artifacts cannot leak signing material.

Coordinate generalized GitHub Actions trusted-execution concerns with #506/#510 rather than inventing a separate workflow-policy engine here.


11. Qt migration relationship

This contract must survive the Tauri→Qt transition.

Separate:

PRODUCT RELEASE TRUST CONTRACT
        = durable

TAURI PACKAGING IMPLEMENTATION
        = transitional

QT PACKAGING IMPLEMENTATION
        = future adapter to the same contract

Do not defer OS signing/notarization merely because Tauri is transitional: current users download current installers today.

Conversely, do not build a Tauri-specific signing abstraction that Qt cannot replace cleanly.

Before Qt Stable, the Qt packaging lane must prove equivalent or stronger:

  • artifact identity;
  • native code signing/notarization;
  • updater/update trust if Qt uses an updater;
  • rollback/revocation;
  • least-privilege CI;
  • packaged verification.

12. Documentation truth

After implementation, reconcile:

Use precise vocabulary:

SIGNED UPDATER PAYLOAD
AUTHENTICODE-SIGNED INSTALLER
APPLE-DEVELOPER-ID-SIGNED APP
NOTARIZED / STAPLED
PROVENANCE-ATTESTED BUILD

Never collapse them into generic "signed".


Acceptance criteria

Non-goals

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions