From da8493f25f31fa449e2e173674d3531911d42ba8 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 16 Apr 2026 17:57:39 +0200 Subject: [PATCH] add release documentation --- .github/workflows/RELEASE.md | 189 +++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 .github/workflows/RELEASE.md diff --git a/.github/workflows/RELEASE.md b/.github/workflows/RELEASE.md new file mode 100644 index 000000000..5020ca997 --- /dev/null +++ b/.github/workflows/RELEASE.md @@ -0,0 +1,189 @@ +# Cryptomator Release Workflow + +This document describes the automated release pipeline defined in [`draft-release.yml`](draft-release.yml) and [`post-publish.yml`](post-publish.yml). + +## Overview + +The release process has two phases: + +1. **Draft phase** (`draft-release.yml`) -- triggered by pushing a signed git tag. Compiles, tests, builds platform installers, and creates a **draft** GitHub Release. +2. **Post-publish phase** (`post-publish.yml`) -- triggered when the draft release is manually **published**. Submits Windows installers for AV whitelisting, notifies the team for DEB build and latest-version update, and triggers downstream updates (website, docs, winget). + +```mermaid +--- +config: + htmlLabels: false +--- +flowchart TD + %% ── Trigger ────────────────────────────────────────────── + push_tag([🏷 Signed tag pushed]) + + %% ── Draft phase ────────────────────────────────────────── + push_tag --> get-version + + subgraph draft["draft-release.yml"] + get-version["get-version + *parse semver from tag*"] + + get-version --> create-release + create-release["create-release + *compile & test (Linux) + create draft release + sign source tarball*"] + + create-release --> build-exe-and-msi + create-release --> build-dmg-arm64 + create-release --> build-dmg-x64 + create-release --> build-appimages + + build-exe-and-msi["build-exe-and-msi + *calls win-exe.yml + MSI + EXE (x64) + code-signed & GPG-signed*"] + build-dmg-arm64["build-dmg-arm64 + *calls mac-dmg.yml + DMG (arm64) + notarized & GPG-signed*"] + build-dmg-x64["build-dmg-x64 + *calls mac-dmg-x64.yml + DMG (x64) + notarized & GPG-signed*"] + build-appimages["build-appimages + *calls appimage.yml + AppImage (x86_64 + aarch64) + GPG-signed*"] + + build-exe-and-msi --> update-sha256sums + build-dmg-arm64 --> update-sha256sums + build-dmg-x64 --> update-sha256sums + build-appimages --> update-sha256sums + + update-sha256sums["update-sha256sums + *compute checksums + update release body*"] + end + + update-sha256sums --> manual_review + + %% ── Manual gate ────────────────────────────────────────── + manual_review{{Manual review + & publish}} + + %% ── Post-publish phase ─────────────────────────────────── + manual_review --> published([📢 Release published]) + published --> post-publish + + subgraph post-publish["post-publish.yml"] + direction TB + + check-release["check-release + *classify release tag + stable, alpha, beta, rc, unknown*"] + notify["notify + *Slack notifications + deb build & version check*"] + get-asset-urls["get-asset-urls + *extract MSI & EXE + download URLs*"] + + check-release --> notify-winget + check-release --> trigger-website + check-release --> trigger-docs + + get-asset-urls --> allowlist-msi + allowlist-msi --> allowlist-exe + + allowlist-msi["allowlist-msi-x64 + *av-whitelist.yml + Kaspersky & Avast*"] + allowlist-exe["allowlist-exe-x64 + *av-whitelist.yml + Kaspersky & Avast*"] + + notify-winget["notify-winget + *Slack: ready for winget + stable only*"] + trigger-website["trigger-website-update + *dispatch to + cryptomator.github.io + stable only*"] + trigger-docs["trigger-docs-update + *dispatch to + cryptomator/docs + stable only, Windows*"] + end +``` + +## Phase 1: Draft Release (`draft-release.yml`) + +**Trigger:** push of any tag (`*`) + +### Jobs + +| Job | Runs on | Description | +|-----|---------|-------------| +| **get-version** | ubuntu | Parses the tag into semver components (`semVerNum`, `semVerSuffix`, `revNum`, `versionType`). Skips remaining jobs if the version format is unknown. | +| **create-release** | ubuntu | Checks out the repo, verifies the tag is **signed** and lives on a `main` or `release/*` branch. Runs `mvn verify` (with `xvfb-run`). Creates a **draft** GitHub Release using the [release body template](../release-body.md.template). Downloads and GPG-signs the source tarball. | +| **build-exe-and-msi** | windows | Calls [`win-exe.yml`](win-exe.yml). Builds the MSI and EXE bundle installer for x64 Windows. Code-signed via Azure Trusted Signing, GPG-signed, and uploaded to the draft release. Outputs SHA-256 checksums. | +| **build-dmg-arm64** | macos-15 | Calls [`mac-dmg.yml`](mac-dmg.yml). Builds the DMG for Apple Silicon. Code-signed, notarized with Apple, GPG-signed, and uploaded. Outputs SHA-256 checksum. | +| **build-dmg-x64** | macos-15-large | Calls [`mac-dmg-x64.yml`](mac-dmg-x64.yml). Same as above but for Intel Macs. Uses macFUSE instead of FUSE-T. | +| **build-appimages** | ubuntu | Calls [`appimage.yml`](appimage.yml). Builds AppImages for x86_64 and aarch64 (matrix). GPG-signed and uploaded with `.zsync` delta-update files. Outputs SHA-256 checksums. | +| **update-sha256sums** | ubuntu | Runs after all builds complete. Computes the source tarball checksum, collects all artifact checksums, and updates the draft release body via `envsubst`. Replaces the "builds still running" banner with a success notice. | + +### Release Artifacts + +After the draft phase, the GitHub Release contains: + +| Artifact | Platform | +|----------|----------| +| `cryptomator-.tar.gz.asc` | Source (GPG signature) | +| `Cryptomator--x64.msi` + `.asc` | Windows | +| `Cryptomator--x64.exe` + `.asc` | Windows | +| `Cryptomator--arm64.dmg` + `.asc` | macOS (Apple Silicon) | +| `Cryptomator--x64.dmg` + `.asc` | macOS (Intel) | +| `cryptomator--x86_64.AppImage` + `.zsync` + `.asc` | Linux (x86_64) | +| `cryptomator--aarch64.AppImage` + `.zsync` + `.asc` | Linux (aarch64) | + +All artifacts are signed with GPG key [`615D449FE6E6A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a). + +## Manual Review Gate + +After the draft phase completes, a maintainer reviews the draft release on GitHub. This is the point to: + +- Verify all artifacts are present and checksums look correct. +- Edit the auto-generated release notes (What's New, Bugfixes, Other Changes). +- **Publish** the release when ready, which triggers phase 2. + +## Phase 2: Post-Publish (`post-publish.yml`) + +**Trigger:** `release: [published]` + +### Jobs + +| Job | Condition | Description | +|-----|-----------|-------------| +| **notify** | always | Sends Slack notifications to `#cryptomator-desktop`: ready to build `.deb` package, and reminder to update `latest-version.json` on S3. | +| **get-asset-urls** | always | Extracts MSI and EXE download URLs from the release assets. | +| **check-release** | always | Classifies the published release tag as `stable`, `alpha`, `beta`, `rc`, or `unknown`. Stable-only follow-up jobs depend on this output. Unlike `get-version.yml`, this job does not perform semver validation. | +| **allowlist-msi-x64** | Windows release | Calls [`av-whitelist.yml`](av-whitelist.yml). Uploads the MSI to Kaspersky and Avast for whitelisting. | +| **allowlist-exe-x64** | Windows release | Same as above for the EXE. Runs sequentially after MSI. | +| **notify-winget** | stable + Windows | Sends a Slack notification that the release is ready for [winget submission](winget.yml). | +| **trigger-website-update** | stable | Dispatches `desktop-release` event to `cryptomator/cryptomator.github.io`. | +| **trigger-docs-update** | stable + Windows | Dispatches `desktop-release` event to `cryptomator/docs`. | + +### Manual Follow-ups + +These steps are triggered by team members after Slack notifications: + +- **Debian package** -- Run the [`debian.yml`](debian.yml) workflow to build `.deb` and optionally upload to the PPA. +- **winget** -- Run the [`winget.yml`](winget.yml) workflow to submit to the Windows Package Manager. +- **latest-version.json** -- Update the version-check file on S3 (`static.cryptomator.org/desktop/latest-version.json`). + +## Signing & Security + +- **Git tag** must be SSH-signed and reside on `main` or `release/*`. +- **Windows** installers are code-signed using Azure Trusted Signing. +- **macOS** DMGs are code-signed with an Apple Developer certificate and notarized via `notarytool`. +- **All artifacts** receive a detached GPG signature (`.asc`) using key `615D449FE6E6A235`. +- **AV whitelisting** is submitted to Kaspersky and Avast after publish (Windows installers only). +- The draft release is created using `CRYPTOBOT_RELEASE_TOKEN`, not `GITHUB_TOKEN`, to ensure proper permissions and trigger downstream workflows.