Compare commits

...

118 Commits

Author SHA1 Message Date
Armin Schrenk
e5fe5604c3 improve documentation of fusermount3 flatpak script 2026-05-06 16:26:31 +02:00
Armin Schrenk
74f36f20ea remove legacy fuse2 stuff 2026-05-05 17:49:22 +02:00
jose-cardoso-a22506616
472b10a8a4 Merge pull request #4228 from jose-cardoso-a22506616/issue-3993
Closes #3993
2026-05-04 08:50:10 +02:00
Armin Schrenk
2fe7fe886c Merge pull request #4227 from yugui923/fix/vault-options-mount-scroll
fix(ui): make vault options mounting tab scrollable
2026-04-27 14:50:46 +02:00
Armin Schrenk
459112f5b8 Fix release workflow
"workflow_call" is not a event name
2026-04-27 13:01:13 +02:00
Armin Schrenk
ea86124c7d Merge pull request #4205 from cryptomator/feature/immutable-releases
Feature: Refactor Release pipeline to allow immutable releases
2026-04-27 09:22:01 +02:00
Yuri Gui
cd9e315447 fix(ui): make Vault Options "Mounting" tab scrollable
Wrap the mounting-options VBox in a ScrollPane so that conditionally
shown rows (drive-letter selector, custom mount-point picker, custom
mount flags) remain reachable when the Vault Options window is at or
near its 300px minimum height. Previously the rows were clipped past
the bottom of the tab with no scrollbar, forcing the user to enlarge
the window manually before the controls could be seen or interacted
with.

Fixes #3150

Co-Authored-By: Yuri Gui <yugui923@users.noreply.github.com>
2026-04-25 14:41:28 +00:00
Armin Schrenk
1266926ebb fix docs
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2026-04-24 15:39:05 +02:00
Armin Schrenk
1e6bc1f043 Update RELEASE doc
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2026-04-24 15:10:57 +02:00
Armin Schrenk
1230e787a9 Update RELEASE.md
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2026-04-21 15:36:54 +02:00
Armin Schrenk
da8493f25f add release documentation 2026-04-16 17:57:39 +02:00
Armin Schrenk
4a0a4309c2 Replace get-version workflow call with slim job 2026-04-16 17:53:08 +02:00
Armin Schrenk
c52ae0120d update changelog 2026-04-16 17:51:15 +02:00
Armin Schrenk
e6cef947c1 rename job 2026-04-16 17:51:06 +02:00
Armin Schrenk
08009ca1a0 Merge branch 'develop' into feature/immutable-releases
# Conflicts:
#	.github/workflows/appimage.yml
#	.github/workflows/mac-dmg-x64.yml
#	.github/workflows/mac-dmg.yml
#	.github/workflows/win-exe.yml
2026-04-14 12:14:23 +02:00
Armin Schrenk
d27a52752b improve readability of version splitting 2026-04-14 11:40:02 +02:00
Armin Schrenk
c745fca2ea update draft-release.yml
adhere to new workflow_call api
2026-04-13 17:58:18 +02:00
Armin Schrenk
d1fcf528b0 use pwsh to move reattach burn engine 2026-04-13 17:40:43 +02:00
Armin Schrenk
b6133e481c Refactor appimage, dmg and msi/exe workflows
* unify inputs handling for worklfow dispatch and call
* simplify conditions for signing/release steps
2026-04-13 16:27:12 +02:00
LamTrinh.Dev
d67aa9c10a + Update Copyright year from "2016 - 2025" to "2016-2026". (#4218)
* + Update Copyright year from "2016 - 2025" to "2016-2026".
2026-04-13 15:30:33 +02:00
Armin Schrenk
19a9595f2e rename worfklow to clearly indicate what it does 2026-04-13 11:46:03 +02:00
Armin Schrenk
f21ae0e11c fix notarization of dmg files on workflow calls 2026-04-13 11:37:51 +02:00
Armin Schrenk
54f805a0c9 fix exe installer not found after 2026-04-09 17:18:07 +02:00
Armin Schrenk
aa239418cf use more local environment instead of copying data into script 2026-04-09 16:57:30 +02:00
Armin Schrenk
8f0c6eb994 fix bugs
* win-exe still checked for release event
* only perform appimage checksum step on release
* remove unused input in appimage flow
2026-04-09 16:55:08 +02:00
Armin Schrenk
4751c81d06 adjust hub-url in share vault dialog 2026-04-08 16:49:11 +02:00
Armin Schrenk
0e1132133c replace guava cache with caffeine 2026-04-08 16:23:25 +02:00
Armin Schrenk
c7d77091f5 Merge branch 'develop' into feature/immutable-releases
# Conflicts:
#	.github/workflows/appimage.yml
#	.github/workflows/build.yml
#	.github/workflows/mac-dmg-x64.yml
#	.github/workflows/mac-dmg.yml
#	.github/workflows/post-publish.yml
2026-04-08 16:08:23 +02:00
Armin Schrenk
3a4039d663 use ubuntu-slim runner for small tasks 2026-04-08 13:00:23 +02:00
Armin Schrenk
f94d204604 cleanup 2026-04-08 12:57:32 +02:00
Armin Schrenk
d76dbe0ddb Replace automatic version file update
by simple notification
2026-04-08 12:54:27 +02:00
Armin Schrenk
235a23ce77 fix check for tag belongs to main or release branch 2026-04-08 12:38:23 +02:00
Armin Schrenk
357b30684b point to correct release workflow file in template 2026-04-08 12:37:50 +02:00
Armin Schrenk
517e12a586 pin jdk version for release 2026-04-08 12:35:54 +02:00
Armin Schrenk
96aa8fe180 add pkgrel update step for aur-bin 2026-04-07 17:20:08 +02:00
Armin Schrenk
7bffc317ff rename workflow from release to create-release
to prevent confusion with github release.yml standard
2026-04-07 17:05:30 +02:00
Armin Schrenk
7dde389671 move aur-bin PR creation into own workflow 2026-04-07 17:04:56 +02:00
dependabot[bot]
a40f17e8f1 Bump the github-actions group with 5 updates (#4207)
Bumps the github-actions group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [softprops/action-gh-release](https://github.com/softprops/action-gh-release) | `2.5.0` | `2.6.1` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `8.0.0` | `8.0.1` |
| [actions/cache](https://github.com/actions/cache) | `5.0.3` | `5.0.4` |
| [skymatic/semver-validation-action](https://github.com/skymatic/semver-validation-action) | `3.0.0` | `4.0.0` |
| [vedantmgoyal2009/winget-releaser](https://github.com/vedantmgoyal2009/winget-releaser) | `19e706d4c9121098010096f9c495a70a7518b30f` | `7bd472be23763def6e16bd06cc8b1cdfab0e2fd5` |


Updates `softprops/action-gh-release` from 2.5.0 to 2.6.1
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](a06a81a03e...153bb8e044)

Updates `actions/download-artifact` from 8.0.0 to 8.0.1
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](70fc10c6e5...3e5f45b2cf)

Updates `actions/cache` from 5.0.3 to 5.0.4
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](cdf6c1fa76...668228422a)

Updates `skymatic/semver-validation-action` from 3.0.0 to 4.0.0
- [Release notes](https://github.com/skymatic/semver-validation-action/releases)
- [Commits](7a6ae1c9e1...7c80b6b03a)

Updates `vedantmgoyal2009/winget-releaser` from 19e706d4c9121098010096f9c495a70a7518b30f to 7bd472be23763def6e16bd06cc8b1cdfab0e2fd5
- [Release notes](https://github.com/vedantmgoyal2009/winget-releaser/releases)
- [Commits](19e706d4c9...7bd472be23)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/cache
  dependency-version: 5.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: skymatic/semver-validation-action
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: vedantmgoyal2009/winget-releaser
  dependency-version: 7bd472be23763def6e16bd06cc8b1cdfab0e2fd5
  dependency-type: direct:production
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-07 11:39:43 +02:00
Copilot
699e22d31a chore: Consolidate dependabot maven groups and switch to monthly schedule (#4208)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: infeo <9036915+infeo@users.noreply.github.com>
2026-04-02 16:58:12 +02:00
Armin Schrenk
5d5b9137cc fix workflows 2026-04-01 16:38:07 +02:00
Armin Schrenk
02767b0caf pin aws-configure action 2026-04-01 16:29:59 +02:00
Armin Schrenk
ddd8c572e7 prevent accidental releases of unsigend tags 2026-04-01 16:27:20 +02:00
Armin Schrenk
aa8ccf53df remove manual trigger for workflow 2026-04-01 16:16:46 +02:00
Armin Schrenk
c199561a9e Link to the changelog of the git tag
in the release notes
2026-04-01 16:10:26 +02:00
Armin Schrenk
e341983ffe add update-latest-version job to post-publish 2026-04-01 14:14:33 +02:00
Armin Schrenk
f10b28ecb1 fix typos 2026-03-31 18:11:41 +02:00
Armin Schrenk
95eed96a37 gate windows specifc post-publishes task with check
for windows artifacts in release
2026-03-31 16:02:32 +02:00
mindmonk
9de0981594 Merge pull request #4164 from cryptomator/feature/decrypt-name-single-dialog-per-vault
Fix Decrypt File Name dialog to reuse a single window
2026-03-31 11:02:13 +02:00
Armin Schrenk
4d6ce70afe Merge branch 'develop' into feature/immutable-releases
# Conflicts:
#	.github/workflows/appimage.yml
#	.github/workflows/mac-dmg-x64.yml
#	.github/workflows/mac-dmg.yml
#	.github/workflows/win-exe.yml
2026-03-30 15:37:06 +02:00
Armin Schrenk
e75deb282c use correct cmd
for computing sha sum
2026-03-30 15:33:24 +02:00
Jan-Peter Klein
87fe209b54 Merge branch 'develop' into feature/decrypt-name-single-dialog-per-vault 2026-03-30 12:47:55 +02:00
Jan-Peter Klein
21cffb13c7 remove unused initialList field from DecryptFileNamesViewController 2026-03-30 12:46:11 +02:00
Armin Schrenk
ee92cc4e9f Add docs update workflow 2026-03-30 12:22:03 +02:00
Jan-Peter Klein
9eca05aeb7 address infeos review: drop paths injection, close on locked vault, clear mapping on close 2026-03-30 12:15:09 +02:00
Armin Schrenk
57c84627f9 Update release draft with sed and envsubst
instead of awk
2026-03-30 12:07:08 +02:00
Armin Schrenk
a653fc3627 Merge pull request #4199 from cryptomator/feature/ci-build-flatpak
Feature: Build flatpak on CI
2026-03-27 15:30:48 +01:00
Armin Schrenk
db31fcad98 fix flatpak/cryptomator module git error 2026-03-27 13:39:48 +01:00
Armin Schrenk
b82c73f789 decouple build script from app source
additionally, check tag if a PR should be created
2026-03-26 18:18:04 +01:00
Armin Schrenk
70d3507e5d also tie this workflow to get-version workflow 2026-03-26 17:39:05 +01:00
Armin Schrenk
518b45d149 checkout the correct repository 2026-03-26 17:38:31 +01:00
mindmonk
65f2eea6c9 Merge pull request #4194 from cryptomator/feature/hide-update-warning-when-no-update-available
Hide "lock vaults" warning when no update is available
2026-03-26 17:33:25 +01:00
Jan-Peter Klein
12a4a8218a change warning visibility check to use isUpdateAvailable 2026-03-26 12:41:15 +01:00
Armin Schrenk
76dd4f079c use correct cache key 2026-03-26 11:02:08 +01:00
Armin Schrenk
309a8fc705 adjust repository dispatch for website update
* change event type to desktop-release
* add client payload
2026-03-26 10:48:47 +01:00
Armin Schrenk
0b77e6ce04 use release object in event payload 2026-03-25 23:15:13 +01:00
Armin Schrenk
d22e912ca4 fix wrong webhook 2026-03-25 15:14:35 +01:00
Armin Schrenk
690726efc3 adjust post-publish
* run av-whitelist after publish
* notify winget
* remove gpg signature creation
2026-03-25 11:43:58 +01:00
Armin Schrenk
d9c0c4980b add release flow to create releases 2026-03-25 11:42:26 +01:00
Armin Schrenk
4e5eef5a16 remove release drafting from build flow 2026-03-25 11:41:54 +01:00
Armin Schrenk
81b2081033 fix outputs typo in appimage flow 2026-03-25 11:41:38 +01:00
Armin Schrenk
b35fb011e0 fix wrong env variable 2026-03-25 11:03:56 +01:00
Armin Schrenk
fa1e9c7ca7 [skip ci] add comment for envsubst usage 2026-03-25 11:02:32 +01:00
Armin Schrenk
75bb64b333 add permissions 2026-03-24 17:01:22 +01:00
Armin Schrenk
1f40045b41 ensure correct source is used for checkout 2026-03-24 16:55:27 +01:00
Armin Schrenk
1951e5e82c ensure correct revision 2026-03-24 16:20:33 +01:00
Armin Schrenk
0be39c5b7d [skip ci] fix typo 2026-03-24 13:21:25 +01:00
Armin Schrenk
6886188ff4 remove manual update script 2026-03-24 13:05:42 +01:00
Armin Schrenk
3a2de81369 do not use placeholder files 2026-03-24 12:37:10 +01:00
Armin Schrenk
4de3ea2892 add verification step 2026-03-24 12:22:46 +01:00
Armin Schrenk
0beb2e3334 adjust flathub pr job
* add boolean dispatch input to create pr manually
* remove tarball job
* adjust template build script to final build file
* change PR description
* fix slack webhook
2026-03-24 12:15:41 +01:00
Armin Schrenk
537d79f3c2 activate all runners again 2026-03-24 10:57:32 +01:00
Armin Schrenk
10d5f4f530 rename job 2026-03-24 10:57:08 +01:00
Armin Schrenk
ab0e7e1ea9 fix pattern matching and make flow easier to read 2026-03-23 17:53:33 +01:00
Armin Schrenk
967a3aa10b ensure to download correct javafx jars 2026-03-23 16:47:18 +01:00
Armin Schrenk
821649c821 [debug] replace natsort with sort 2026-03-23 15:36:36 +01:00
Armin Schrenk
7cf75e9dba use SNAPSHOT version of flatpak action
and keep build dirs
2026-03-23 11:18:38 +01:00
Armin Schrenk
dfe126f827 update maven dependency source file 2026-03-23 11:10:03 +01:00
Armin Schrenk
80ce98991c use correct runner for every arch 2026-03-23 10:48:53 +01:00
Armin Schrenk
579d42ec74 try x86 runner 2026-03-20 18:42:40 +01:00
Armin Schrenk
047108683f use as base repo the flathub repo 2026-03-20 18:20:15 +01:00
Armin Schrenk
830c9196e7 activate build flatpak step again 2026-03-20 18:10:38 +01:00
Armin Schrenk
7208f23da1 fix type 2026-03-20 18:04:09 +01:00
Armin Schrenk
b0a4a0bcfa add debugging code 2026-03-20 17:59:45 +01:00
Armin Schrenk
f7b13dd121 Use flathub repo
remove yq edits and simply override build yaml
2026-03-20 17:51:10 +01:00
Armin Schrenk
a5ccfa01d2 use yq action
not available in flathub container
2026-03-20 17:26:04 +01:00
Armin Schrenk
62bf4c5b45 fix prepare step 2026-03-20 17:06:42 +01:00
Armin Schrenk
7168d7e31d deactivate x86 runner during development 2026-03-20 16:54:50 +01:00
Armin Schrenk
3c633f8a34 move all build scripts into flatpak-build dir
* additionally, remove maven-dependencies
2026-03-20 16:54:05 +01:00
Armin Schrenk
b606a4ee8e use FreeDesktop runtime 2026-03-20 16:44:29 +01:00
Armin Schrenk
1af094692f run also on certain push events 2026-03-20 16:25:51 +01:00
Armin Schrenk
c86d8ac6b8 build flatpak on CI 2026-03-20 16:22:35 +01:00
Armin Schrenk
b06d65ab43 Merge branch 'main' into develop
# Conflicts:
#	pom.xml
2026-03-20 08:15:31 +01:00
Armin Schrenk
5a0d15c937 Merge pull request #4187 from cryptomator/feature/monthly-dist-builds
Feature: Monthly distribution builds
2026-03-17 13:18:37 +01:00
Jan-Peter Klein
53757dab93 fix unlocked vault warning shown without an available update 2026-03-16 14:22:23 +01:00
Armin Schrenk
e1d4d3e85b fix webhook in workflow 2026-03-13 18:03:19 +01:00
Armin Schrenk
859fe238b8 also test signing step in monthly builds 2026-03-13 17:51:22 +01:00
Armin Schrenk
23df40796b build release artifacts monthly 2026-03-13 17:50:53 +01:00
Armin Schrenk
b98b1326b2 Merge pull request #4147 from cryptomator/feature/dagger-fixes
fix dagger binding graph
2026-03-13 17:39:29 +01:00
Armin Schrenk
2f8831b561 faster initialization 2026-03-13 17:29:59 +01:00
Armin Schrenk
4948b9b586 prevent data races 2026-03-13 17:06:50 +01:00
Armin Schrenk
838018e72e Remove Actalis code signing (#4169) 2026-03-13 16:49:37 +01:00
Sebastian Stenzel
d5433e7a3f CHANGELOG.md: moved security fixes to subsection
[ci skip]
2026-03-13 10:50:20 +01:00
Armin Schrenk
194e19bf5e [skip ci] reset to snapshot version 2026-03-12 14:37:17 +01:00
Armin Schrenk
1358e7098d Merge branch 'main' into develop 2026-03-12 14:35:39 +01:00
Armin Schrenk
d9134b49ad add workflow_call to release artifact workflows 2026-03-06 17:11:11 +01:00
Jan-Peter Klein
92d11d8bd5 Merge branch 'develop' into feature/decrypt-name-single-dialog-per-vault 2026-03-02 14:18:15 +01:00
Jan-Peter Klein
300a811510 fix decrypt file name dialog to reuse one window per vault 2026-03-02 13:39:38 +01:00
Armin Schrenk
84a966993f fix dagger binding graph 2026-02-18 16:24:22 +01:00
41 changed files with 1650 additions and 606 deletions

View File

@@ -3,10 +3,7 @@ updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "Etc/UTC"
interval: "monthly"
ignore:
- dependency-name: "org.cryptomator:integrations-api"
versions: ["2.0.0-alpha1"]
@@ -18,36 +15,9 @@ updates:
- dependency-name: "org.apache.maven.plugins:maven-surefire-plugin"
versions: [ "3.5.4", "3.5.5" ]
groups:
java-test-dependencies:
patterns:
- "org.junit.jupiter:*"
- "org.mockito:*"
- "org.hamcrest:*"
- "com.google.jimfs:jimfs"
maven-build-plugins:
patterns:
- "org.apache.maven.plugins:*"
- "org.jacoco:jacoco-maven-plugin"
- "org.owasp:dependency-check-maven"
- "me.fabriciorby:maven-surefire-junit5-tree-reporter"
- "org.codehaus.mojo:license-maven-plugin"
javafx:
patterns:
- "org.openjfx:*"
java-production-dependencies:
maven-dependencies:
patterns:
- "*"
exclude-patterns:
- "org.openjfx:*"
- "org.apache.maven.plugins:*"
- "org.jacoco:jacoco-maven-plugin"
- "org.owasp:dependency-check-maven"
- "me.fabriciorby:maven-surefire-junit5-tree-reporter"
- "org.codehaus.mojo:license-maven-plugin"
- "org.junit.jupiter:*"
- "org.mockito:*"
- "org.hamcrest:*"
- "com.google.jimfs:jimfs"
- package-ecosystem: "github-actions"
directory: "/" # even for `.github/workflows`

34
.github/release-body.md.template vendored Normal file
View File

@@ -0,0 +1,34 @@
<!-- HEADER -->
> [!WARN]
> 🚧 DO NOT EDIT 🚧
>
> The [builds are still running](https://github.com/cryptomator/cryptomator/actions/workflows/create-release.yml).
> This banner will be replaced after the builds are finished.
<!-- /HEADER -->
<!--REPLACE with auto-generated release notes (see below)
### What's New 🎉
### Bugfixes 🐛
### Other Changes 📎
END REPLACE-->
For a comprehensive view of changes, read the [CHANGELOG](https://github.com/cryptomator/cryptomator/blob/$VERSION/CHANGELOG.md).
---
💾 SHA-256 checksums of release artifacts:
```
$TARBALL
$EXE
$MSI
$DMG_x64
$DMG_arm64
$APPIMAGE_x86_64
$APPIMAGE_aarch64
```
> [!TIP]
> You can verify the GPG signature of all assets using our public key: [`5811 7AFA 1F85 B3EE C154 677D 615D 449F E6E6 A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a).
<!-- Auto-Generated Release Notes: -->

189
.github/workflows/RELEASE.md vendored Normal file
View File

@@ -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-draft
create-release-draft["create-release-draft
*compile & test (Linux)
create draft release
sign source tarball*"]
create-release-draft --> build-exe-and-msi
create-release-draft --> build-dmg-arm64
create-release-draft --> build-dmg-x64
create-release-draft --> 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`). The release is aborted if not an alpha, beta, rc or 'stable' release. |
| **create-release-draft** | 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 GitHub Release **draft** 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-<ver>.tar.gz.asc` | Source (GPG signature) |
| `Cryptomator-<ver>-x64.msi` + `.asc` | Windows |
| `Cryptomator-<ver>-x64.exe` + `.asc` | Windows |
| `Cryptomator-<ver>-arm64.dmg` + `.asc` | macOS (Apple Silicon) |
| `Cryptomator-<ver>-x64.dmg` + `.asc` | macOS (Intel) |
| `cryptomator-<ver>-x86_64.AppImage` + `.zsync` + `.asc` | Linux (x86_64) |
| `cryptomator-<ver>-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` workflow, 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.

View File

@@ -1,17 +1,44 @@
name: Build AppImage
on:
release:
types: [published]
schedule:
- cron: '0 23 20 * *'
workflow_call:
inputs:
semVerNum:
type: string
description: 'The Major.Minor.Patch part of the version'
required: true
revisionNum:
type: string
description: 'The revision number'
required: true
semVerSuffix:
type: string
description: 'The suffix of the version, including dash'
required: true
upload-to-draft:
type: boolean
default: true
outputs:
sha256-appimage-x64:
description: "SHA256 sum of the x64 appimage"
value: ${{ jobs.collect-sha256sums.outputs.x64-sha256sum}}
sha256-appimage-aarch64:
description: "SHA256 sum of the aarch64 appimage"
value: ${{ jobs.collect-sha256sums.outputs.aarch64-sha256sum}}
workflow_dispatch:
inputs:
version:
description: 'Version'
semVerNum:
description: 'The Major.Minor.Patch part of the version'
required: false
create-pr:
description: 'Create a PR for aur-bin repo'
type: boolean
default: false
revisionNum:
description: 'The revision number'
required: false
semVerSuffix:
description: 'The suffix of the version, including dash'
required: false
default: '-SNAPSHOT'
push:
branches-ignore:
- 'dependabot/**'
@@ -24,21 +51,15 @@ on:
env:
JAVA_DIST: 'temurin'
JAVA_VERSION: '25.0.2+10.0.LTS'
VERSION_NUM: ${{ inputs.semVerNum || '99.99.99'}}
REVISION_NUM: ${{ inputs.revisionNum || '0' }}
VERSION_SUFFIX: ${{ inputs.semVerSuffix || ''}}
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.version }} #okay if not defined
build:
name: Build AppImage
runs-on: ${{ matrix.os }}
needs: [get-version]
env:
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
SEMVER_NUM: ${{ needs.get-version.outputs.semVerNum }}
REV_NUM: ${{ needs.get-version.outputs.revNum }}
strategy:
fail-fast: false
matrix:
@@ -83,7 +104,7 @@ jobs:
exit 1
fi
- name: Set version
run : mvn versions:set -DnewVersion="$SEMVER_STR"
run : mvn versions:set -DnewVersion="${VERSION_NUM}${VERSION_SUFFIX}"
- name: Run maven
run: mvn -B clean package -Plinux -DskipTests
- name: Patch target dir
@@ -125,13 +146,13 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2025 Skymatic GmbH"
--app-version "${SEMVER_NUM}.${REV_NUM}"
--copyright "(C) 2016 - 2026 Skymatic GmbH"
--app-version "${VERSION_NUM}.${REVISION_NUM}"
--java-options "--enable-preview"
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator"
--java-options "-Xss5m"
--java-options "-Xmx256m"
--java-options "-Dcryptomator.appVersion=\"${SEMVER_STR}\""
--java-options "-Dcryptomator.appVersion=\"${VERSION_NUM}${VERSION_SUFFIX}\""
--java-options "-Dfile.encoding=\"utf-8\""
--java-options "-Djava.net.useSystemProxies=true"
--java-options "-Dcryptomator.adminConfigPath=\"/etc/cryptomator/config.properties\""
@@ -142,7 +163,7 @@ jobs:
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\""
--java-options "-Dcryptomator.showTrayIcon=true"
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\""
--java-options "-Dcryptomator.buildNumber=\"appimage-${REV_NUM}\""
--java-options "-Dcryptomator.buildNumber=\"appimage-${REVISION_NUM}\""
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\""
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log"
@@ -181,7 +202,7 @@ jobs:
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
- name: Build AppImage
run: >
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${SEMVER_STR}-${{ matrix.arch }}.AppImage
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.arch }}.AppImage
-u "gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${{ matrix.arch }}.AppImage.zsync"
--sign --sign-key=615D449FE6E6A235
- name: Create detached GPG signatures
@@ -198,9 +219,10 @@ jobs:
cryptomator-*.asc
if-no-files-found: error
- name: Publish AppImage on GitHub Releases
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
if: inputs.upload-to-draft
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
with:
draft: true
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
files: |
@@ -208,79 +230,24 @@ jobs:
cryptomator-*.zsync
cryptomator-*.asc
create-aur-bin-pr:
name: Create PR for aur-bin repo
if: github.event_name == 'workflow_dispatch' && inputs.create-pr || github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable'
collect-sha256sums:
name: Collect AppImage checksums
runs-on: ubuntu-latest
needs: [build, get-version]
container:
image: archlinux:base-devel
env:
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
PKGDEST: ${{ github.workspace }}/pkgdest
SRCDEST: ${{ github.workspace }}/srcdest
needs: [build]
if: inputs.upload-to-draft
outputs:
x64-sha256sum: ${{ steps.sha256sum.outputs.x64-sha256sum }}
aarch64-sha256sum: ${{ steps.sha256sum.outputs.aarch64-sha256sum }}
steps:
- name: Prepare pacman
run: |
pacman-key --init
pacman-key --populate archlinux
pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip github-cli curl pacman-contrib
- name: Checkout cryptomator/aur-bin
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Download AppImage artifacts
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
repository: 'cryptomator/aur-bin'
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Create build user
pattern: appimage-*
path: appimage-artifacts
- name: Compute SHA256 sums
id: sha256sum
run: |
useradd -m builder
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder
chown -R builder:builder "$GITHUB_WORKSPACE"
install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST"
- name: Import Cryptomator release signing key
# try first ubuntu. on failure try openpgp keyservers
run: >
sudo -u builder gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
|| sudo -u builder gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
- name: Checkout release branch
run: |
git config --global safe.directory '*'
git checkout -b "release/${SEMVER_STR}"
- name: Update build file
run: |
sed -i -e "s|^pkgver=.*$|pkgver=${SEMVER_STR}|" PKGBUILD
sed -i -e 's|^pkgrel=.*$|pkgrel=1|' PKGBUILD
sudo -u builder updpkgsums
sudo -u builder makepkg --printsrcinfo > .SRCINFO
- name: Build package with makepkg
run: >
sudo -u builder
env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST"
makepkg --syncdeps --cleanbuild --noconfirm --log
- name: Commit and push
run: |
git config user.name "cryptobot"
git config user.email "cryptobot@users.noreply.github.com"
git config push.autoSetupRemote true
git stage PKGBUILD .SRCINFO
git commit -m "Prepare release ${SEMVER_STR}"
git push
- name: Create pull request
id: create-pr
run: |
printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md
PR_URL=$(gh pr create --title "Release ${SEMVER_STR}" --body-file pr_body.md)
echo "url=$PR_URL" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "AUR-bin release PR for ${{ github.event.repository.name }} ${{ needs.get-version.outputs.semVerStr }} created."
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed."
SLACK_FOOTER: false
MSG_MINIMAL: true
read -ra X64_SUM < <(sha256sum appimage-artifacts/appimage-x86_64/cryptomator-*-x86_64.AppImage)
read -ra AARCH64_SUM < <(sha256sum appimage-artifacts/appimage-aarch64/cryptomator-*-aarch64.AppImage)
echo "x64-sha256sum=${X64_SUM[0]}" >> "$GITHUB_OUTPUT"
echo "aarch64-sha256sum=${AARCH64_SUM[0]}" >> "$GITHUB_OUTPUT"

115
.github/workflows/aur-bin.yml vendored Normal file
View File

@@ -0,0 +1,115 @@
name: PR for aur-bin repo
on:
release:
types: [published]
workflow_dispatch:
inputs:
src-tag:
description: 'Source or Release tag'
required: false
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.src-tag }}
create-aur-bin-pr:
name: Create PR for aur-bin repo
if: (github.event_name == 'workflow_dispatch') || (github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable')
runs-on: ubuntu-latest
needs: [get-version]
container:
image: archlinux:base-devel
env:
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
PKGDEST: ${{ github.workspace }}/pkgdest
SRCDEST: ${{ github.workspace }}/srcdest
steps:
- name: Prepare pacman
run: |
pacman-key --init
pacman-key --populate archlinux
pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip github-cli curl pacman-contrib
- name: Checkout cryptomator/aur-bin
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: 'cryptomator/aur-bin'
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Create build user
run: |
useradd -m builder
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder
chown -R builder:builder "$GITHUB_WORKSPACE"
install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST"
- name: Import Cryptomator release signing key
# try first ubuntu. on failure try openpgp keyservers
run: >
sudo -u builder gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
|| sudo -u builder gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
- name: Checkout release branch
run: |
git config --global safe.directory '*'
git checkout -b "release/${SEMVER_STR}"
- name: Determine pkgrel
id: pkgrel
run: |
CURRENT_VERSION="$(sed -nE 's/^pkgver=(.*)$/\1/p' PKGBUILD | head -n1)"
CURRENT_REL="$(sed -nE 's/^pkgrel=([0-9]+).*$/\1/p' PKGBUILD | head -n1)"
if [[ "$CURRENT_VERSION" == "$TARGET_VERSION" && "$CURRENT_REL" =~ ^[0-9]+$ ]]; then
NEXT_REL=$((CURRENT_REL + 1))
else
NEXT_REL=1
fi
echo "value=${NEXT_REL}" >> "$GITHUB_OUTPUT"
echo "dist-version=${TARGET_VERSION}-${NEXT_REL}" >> "$GITHUB_OUTPUT"
env:
TARGET_VERSION: ${{ needs.get-version.outputs.semVerStr }}
- name: Update build file
run: |
sed -i -e "s|^pkgver=.*$|pkgver=${PKG_VERSION}|" PKGBUILD
sed -i -e "s|^pkgrel=.*$|pkgrel=${PKG_RELEASE}|" PKGBUILD
sudo -u builder updpkgsums
sudo -u builder makepkg --printsrcinfo > .SRCINFO
env:
PKG_VERSION: ${{ needs.get-version.outputs.semVerNum }}
PKG_RELEASE: ${{ steps.pkgrel.outputs.value }}
- name: Build package with makepkg
run: >
sudo -u builder
env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST"
makepkg --syncdeps --cleanbuild --noconfirm --log
- name: Commit and push
run: |
git config user.name "cryptobot"
git config user.email "cryptobot@users.noreply.github.com"
git config push.autoSetupRemote true
git stage PKGBUILD .SRCINFO
git commit -m "Prepare release ${DIST_VERSION}"
git push
env:
DIST_VERSION: ${{ steps.pkgrel.outputs.dist-version }}
- name: Create pull request
id: create-pr
run: |
printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md
PR_URL=$(gh pr create --title "Release ${DIST_VERSION}" --body-file pr_body.md)
echo "url=$PR_URL" >> "$GITHUB_OUTPUT"
env:
DIST_VERSION: ${{ steps.pkgrel.outputs.dist-version }}
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: ''
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "AUR-bin release PR for ${{ github.event.repository.name }} ${{ needs.get-version.outputs.semVerStr }} created."
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed."
SLACK_FOOTER: ''
MSG_MINIMAL: true

View File

@@ -37,7 +37,7 @@ on:
jobs:
download-file:
name: Downloads the file into the VM
runs-on: ubuntu-latest
runs-on: ubuntu-slim
outputs:
fileName: ${{ steps.extractName.outputs.fileName}}
env:
@@ -58,12 +58,12 @@ jobs:
if-no-files-found: error
allowlist-kaspersky:
name: Anti Virus Allowlisting Kaspersky
runs-on: ubuntu-latest
runs-on: ubuntu-slim
needs: download-file
if: inputs.kaspersky
steps:
- name: Download artifact
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.download-file.outputs.fileName }}
path: upload
@@ -78,12 +78,12 @@ jobs:
local-dir: ./upload/
allowlist-avast:
name: Anti Virus Allowlisting Avast
runs-on: ubuntu-latest
runs-on: ubuntu-slim
needs: download-file
if: inputs.avast
steps:
- name: Download artifact
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.download-file.outputs.fileName }}
path: upload

View File

@@ -29,7 +29,7 @@ jobs:
java-version: ${{ env.JAVA_VERSION }}
cache: 'maven'
- name: Cache SonarCloud packages
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
@@ -47,40 +47,3 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- name: Draft a release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
draft: true
discussion_category_name: releases
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
generate_release_notes: true
body: |-
> [!NOTE]
> 🚧 Work in Progress 🚧
>
> Please be patient, the [builds are still running](https://github.com/cryptomator/cryptomator/actions). Binary packages can be found here in a few moments.
<!--REPLACE with auto-generated release notes (see below)
### What's New 🎉
### Bugfixes 🐛
### Other Changes 📎
END REPLACE-->
For a comprehensive view of changes, read the [CHANGELOG](https://github.com/cryptomator/cryptomator/blob/develop/CHANGELOG.md).
---
<!-- Don't forget to include the
💾 SHA-256 checksums of release artifacts:
```
```
-->
> [!TIP]
> You can verify the GPG signature of all assets using our public key: [`5811 7AFA 1F85 B3EE C154 677D 615D 449F E6E6 A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a).
<!-- Auto-Generated Release Notes: -->

View File

@@ -74,10 +74,10 @@ jobs:
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON: ''
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "JDK update available"
SLACK_MESSAGE: "Cryptomator-CI JDK can be upgraded to ${{ steps.determine.outputs.LATEST_JDK_VERSION }}. Check the Nextcloud collective for instructions."
SLACK_FOOTER: false
SLACK_FOOTER: ''
MSG_MINIMAL: true

View File

@@ -1,6 +1,8 @@
name: Build Debian Package
on:
schedule:
- cron: '0 22 20 * *'
workflow_dispatch:
inputs:
semver:

157
.github/workflows/draft-release.yml vendored Normal file
View File

@@ -0,0 +1,157 @@
name: Draft a Cryptomator Release
on:
push:
tags:
- '*'
env:
JAVA_DIST: 'temurin'
JAVA_VERSION: '25.0.2+10.0.LTS'
defaults:
run:
shell: bash
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ''
create-release-draft:
name: Compile and Test
runs-on: ubuntu-latest
needs: get-version
if: needs.get-version.outputs.versionType != 'unknown'
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Check the git tag is signed
run: git cat-file -p "${GITHUB_REF_NAME}" | grep "BEGIN SSH SIGNATURE"
- name: Check the git tag is on release or main branch
run: git branch -r --contains "${GITHUB_REF_NAME}" | grep -E '^\s*origin/(main|release/.*)\s*$'
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}
cache: 'maven'
- name: Build and Test
run: xvfb-run mvn -B verify -Plinux
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
- name: Draft a release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
draft: true
discussion_category_name: releases
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
generate_release_notes: true
body_path: .github/release-body.md.template
- name: Download source tarball
run: |
curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/${{ github.ref }}.tar.gz --output cryptomator-${{ github.ref_name }}.tar.gz
- name: Sign source tarball with key 615D449FE6E6A235
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.tar.gz
env:
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
- name: Publish asc on GitHub Releases
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
draft: true
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
files: |
cryptomator-*.tar.gz.asc
build-exe-and-msi:
needs: [get-version, create-release-draft]
uses: ./.github/workflows/win-exe.yml
with:
semVerNum: ${{needs.get-version.outputs.semVerNum}}
revisionNum: ${{needs.get-version.outputs.revNum}}
semVerSuffix: ${{needs.get-version.outputs.semVerSuffix}}
secrets: inherit
build-dmg-arm64:
needs: [get-version, create-release-draft]
uses: ./.github/workflows/mac-dmg.yml
with:
semVerNum: ${{needs.get-version.outputs.semVerNum}}
revisionNum: ${{needs.get-version.outputs.revNum}}
semVerSuffix: ${{needs.get-version.outputs.semVerSuffix}}
secrets: inherit
build-dmg-x64:
needs: [get-version, create-release-draft]
uses: ./.github/workflows/mac-dmg-x64.yml
with:
semVerNum: ${{needs.get-version.outputs.semVerNum}}
revisionNum: ${{needs.get-version.outputs.revNum}}
semVerSuffix: ${{needs.get-version.outputs.semVerSuffix}}
secrets: inherit
build-appimages:
needs: [get-version, create-release-draft]
uses: ./.github/workflows/appimage.yml
with:
semVerNum: ${{needs.get-version.outputs.semVerNum}}
revisionNum: ${{needs.get-version.outputs.revNum}}
semVerSuffix: ${{needs.get-version.outputs.semVerSuffix}}
secrets: inherit
update-sha256sums:
runs-on: ubuntu-latest
needs: [get-version, build-exe-and-msi, build-dmg-arm64, build-dmg-x64, build-appimages]
env:
TAG: ${{ github.ref_name }}
SEMVER: ${{ needs.get-version.outputs.semVerStr }}
GH_TOKEN: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Compute source tarball SHA256
id: src-sha256
run: |
curl --silent --fail-with-body --proto "=https" -L \
-H "Accept: application/vnd.github+json" \
"https://github.com/cryptomator/cryptomator/archive/refs/tags/${TAG}.tar.gz" \
--output "cryptomator-${SEMVER}.tar.gz"
read -ra CMD_OUTPUT < <(sha256sum "cryptomator-${SEMVER}.tar.gz")
echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT
- name: Update release body with checksums
run: |
CURRENT_BODY=$(gh release view "${TAG}" --json body --jq .body)
RELEASE_BODY=$(printf '%s\n' "${CURRENT_BODY}" | sed '/<!-- HEADER -->/,/<!-- \/HEADER -->/c\
<!-- HEADER -->\
> [!NOTE]\
> Release artifacts finished building successfully.\
>\
> SHA-256 checksums have been updated below.\
<!-- /HEADER -->')
export TARBALL="${SRC_SHA} cryptomator-${SEMVER}.tar.gz"
export MSI="${MSI_SHA} Cryptomator-${SEMVER}-x64.msi"
export EXE="${EXE_SHA} Cryptomator-${SEMVER}-x64.exe"
export DMG_arm64="${DMG_ARM64_SHA} Cryptomator-${SEMVER}-arm64.dmg"
export DMG_x64="${DMG_X64_SHA} Cryptomator-${SEMVER}-x64.dmg"
export APPIMAGE_x86_64="${APPIMAGE_X64_SHA} cryptomator-${SEMVER}-x86_64.AppImage"
export APPIMAGE_aarch64="${APPIMAGE_AARCH64_SHA} cryptomator-${SEMVER}-aarch64.AppImage"
envsubst '$VERSION $TARBALL $EXE $MSI $DMG_x64 $DMG_arm64 $APPIMAGE_x86_64 $APPIMAGE_aarch64' \
<<< "${RELEASE_BODY}" \
> release-body.md
gh release edit "${TAG}" --draft --notes-file release-body.md
env:
VERSION: ${{ needs.get-version.outputs.semVerStr }}
SRC_SHA: ${{ steps.src-sha256.outputs.value }}
MSI_SHA: ${{ needs.build-exe-and-msi.outputs.sha256-msi }}
EXE_SHA: ${{ needs.build-exe-and-msi.outputs.sha256-exe }}
DMG_ARM64_SHA: ${{ needs.build-dmg-arm64.outputs.sha256-dmg }}
DMG_X64_SHA: ${{ needs.build-dmg-x64.outputs.sha256-dmg }}
APPIMAGE_X64_SHA: ${{ needs.build-appimages.outputs.sha256-appimage-x64 }}
APPIMAGE_AARCH64_SHA: ${{ needs.build-appimages.outputs.sha256-appimage-aarch64 }}

View File

@@ -1,85 +0,0 @@
name: Create PR for flathub
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: 'Release tag'
required: true
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.tag }}
tarball:
name: Determines tarball url and compute checksum
runs-on: ubuntu-latest
needs: [get-version]
if: github.event_name == 'workflow_dispatch' || needs.get-version.outputs.versionType == 'stable'
outputs:
url: ${{ steps.url.outputs.url}}
sha512: ${{ steps.sha512.outputs.sha512}}
steps:
- name: Determine tarball url
id: url
run: |
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${TAG}.tar.gz"
echo "url=${URL}" >> "$GITHUB_OUTPUT"
env:
TAG: ${{ inputs.tag || github.event.release.tag_name}}
- name: Download source tarball and compute checksum
id: sha512
run: |
curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" ${{ steps.url.outputs.url }} --output cryptomator.tar.gz
TARBALL_SHA512=$(sha512sum cryptomator.tar.gz | cut -d ' ' -f1)
echo "sha512=${TARBALL_SHA512}" >> "$GITHUB_OUTPUT"
flathub:
name: Create PR for flathub
runs-on: ubuntu-latest
needs: [tarball, get-version]
env:
FLATHUB_PR_URL: tbd
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: 'flathub/org.cryptomator.Cryptomator'
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Checkout release branch
run: |
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
- name: Update build file
run: |
sed -i -e 's/VERSION: [0-9]\+\.[0-9]\+\.[0-9]\+.*/VERSION: ${{ needs.get-version.outputs.semVerStr }}/g' org.cryptomator.Cryptomator.yaml
sed -i -e 's/sha512: [0-9A-Za-z_\+-]\{128\} #CRYPTOMATOR/sha512: ${{ needs.tarball.outputs.sha512 }} #CRYPTOMATOR/g' org.cryptomator.Cryptomator.yaml
sed -i -e 's;url: https://github.com/cryptomator/cryptomator/archive/refs/tags/[^[:blank:]]\+;url: ${{ needs.tarball.outputs.url }};g' org.cryptomator.Cryptomator.yaml
- name: Commit and push
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
git config push.autoSetupRemote true
git stage .
git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}"
git push
- name: Create pull request
run: |
printf "> [!IMPORTANT]\n> Todos:\n> - [ ] Update maven dependencies\n> - [ ] Check for JDK update\n> - [ ] Check for JFX update" > pr_body.md
PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
echo "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_ENV"
env:
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
if: github.event_name == 'release'
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "Flathub release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
SLACK_MESSAGE: "See <${{ env.FLATHUB_PR_URL }}|PR> on how to proceed.>."
SLACK_FOOTER: false
MSG_MINIMAL: true

View File

@@ -14,6 +14,9 @@ on:
semVerNum:
description: "The numerical part of the version string"
value: ${{ jobs.determine-version.outputs.semVerNum}}
semVerSuffix:
description: "The suffix of the version string"
value: ${{ jobs.determine-version.outputs.semVerSuffix}}
revNum:
description: "The revision number"
value: ${{ jobs.determine-version.outputs.revNum}}
@@ -32,6 +35,7 @@ jobs:
outputs:
semVerNum: ${{ steps.versions.outputs.semVerNum }}
semVerStr: ${{ steps.versions.outputs.semVerStr }}
semVerSuffix: ${{ steps.versions.outputs.semVerSuffix }}
revNum: ${{ steps.versions.outputs.revNum }}
type: ${{ steps.versions.outputs.type}}
steps:
@@ -54,25 +58,30 @@ jobs:
else
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
fi
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
SEM_VER_NUM=$(echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/')
SEM_VER_SUFFIX="${SEM_VER_STR#"$SEM_VER_NUM"}"
REVCOUNT=`git rev-list --count HEAD`
TYPE="unknown"
if [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+$ ]]; then
if [[ -z $SEM_VER_SUFFIX ]]; then
TYPE="stable"
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-alpha[1-9]+$ ]]; then
elif [[ $SEM_VER_SUFFIX =~ -alpha[1-9]+$ ]]; then
TYPE="alpha"
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-beta[1-9]+$ ]]; then
elif [[ $SEM_VER_SUFFIX =~ -beta[1-9]+$ ]]; then
TYPE="beta"
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-rc[1-9]$ ]]; then
elif [[ $SEM_VER_SUFFIX =~ -rc[1-9]+$ ]]; then
TYPE="rc"
fi
echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT
echo "semVerNum=${SEM_VER_NUM}" >> $GITHUB_OUTPUT
echo "semVerSuffix=${SEM_VER_SUFFIX}" >> $GITHUB_OUTPUT
echo "revNum=${REVCOUNT}" >> $GITHUB_OUTPUT
echo "type=${TYPE}" >> $GITHUB_OUTPUT
env:
VERSION_STRING: ${{ inputs.version }}
- name: Validate Version
uses: skymatic/semver-validation-action@7a6ae1c9e121540d11c9c7e4e667c83d583aa153 # v3.0.0
uses: skymatic/semver-validation-action@7c80b6b03a18b42884761daa9862ff5683ec8c8a # v4.0.0
with:
version: ${{ steps.versions.outputs.semVerStr }}

264
.github/workflows/linux-flatpak.yml vendored Normal file
View File

@@ -0,0 +1,264 @@
name: Build flatpak
on:
release:
types: [published]
workflow_dispatch:
inputs:
src-tag:
description: 'Source or Release tag'
required: false
create-pr:
description: 'Create Flathub PR'
required: false
type: boolean
default: false
push:
branches-ignore:
- 'dependabot/**'
paths:
- '.github/workflows/get-version.yml'
- '.github/workflows/linux-flatpak.yml'
- 'dist/linux/flatpak/**'
- 'dist/linux/common/**'
- 'dist/linux/resources/**'
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.src-tag }}
build-flatpak:
name: "Build flatpak"
needs: [get-version]
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-25.08
options: --privileged
strategy:
fail-fast: false
matrix:
variant:
- arch: x86_64
runner: ubuntu-24.04
- arch: aarch64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.variant.runner }}
permissions:
contents: read
env:
SRC_GIT_SHA: ${{ inputs.src-tag || github.sha}}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: flathub/org.cryptomator.Cryptomator
submodules: true
- name: Checkout build script
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
path: build-scripts
- name: Checkout app source
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
path: cryptomator
ref: ${{ env.SRC_GIT_SHA }}
fetch-depth: 0
- name: Prepare build files
# using envsubst instead of yq to keep linebreaks
run: |
cp -r -f build-scripts/dist/linux/flatpak/* .
envsubst '$FLATPAK_VERSION $FLATPAK_REVISION $CRYPTOMATOR_SOURCE' < org.cryptomator.Cryptomator.TEMPLATE.yaml > org.cryptomator.Cryptomator.yaml
env:
FLATPAK_VERSION: ${{ needs.get-version.outputs.semVerNum }}
FLATPAK_REVISION: 1
CRYPTOMATOR_SOURCE: |-
type: git
path: cryptomator
commit: ${{ env.SRC_GIT_SHA }}
- name: Copy build script for upload
run: cp org.cryptomator.Cryptomator.yaml org.cryptomator.Cryptomator.${{matrix.variant.arch}}.yaml
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
archive: false
if-no-files-found: error
path: |
org.cryptomator.Cryptomator.${{matrix.variant.arch}}.yaml
- uses: flatpak/flatpak-github-actions/flatpak-builder@401fe28a8384095fc1531b9d320b292f0ee45adb # SNAPSHOT due to using keep-build-dirs
with:
bundle: cryptomator.flatpak
manifest-path: org.cryptomator.Cryptomator.yaml
cache-key: flatpak-builder-${{ env.SRC_GIT_SHA }}
arch: ${{ matrix.variant.arch }}
keep-build-dirs: true
- name: Collect maven dependencies
working-directory: .flatpak-builder/build/cryptomator-1/.m2/repository/
run: |
find * -type f \( -iname '*.jar' -o -iname '*.pom' \) | sort -V > /tmp/maven-dependency-files.txt
grep -v '^org/openjfx/javafx-' /tmp/maven-dependency-files.txt > maven-dependency-files-common.txt
grep '^org/openjfx/javafx-' /tmp/maven-dependency-files.txt > maven-dependency-files-javafx.txt
- name: Update arch independent maven dependencies
run: |
(
cd .flatpak-builder/build/cryptomator-1/.m2/repository/
while IFS= read -r dependencyPath; do
dependencyName=$(dirname "$dependencyPath")
dependencySha=$(sha256sum "$dependencyPath" | cut -c 1-64)
cat <<EOF
- type: file
dest: .m2/repository/${dependencyName}
url: https://repo.maven.apache.org/maven2/${dependencyPath}
sha256: ${dependencySha}
EOF
done < maven-dependency-files-common.txt
) > maven-dependencies.yaml
- name: Update arch specific maven dependencies
run: |
(
cd .flatpak-builder/build/cryptomator-1/.m2/repository/
while IFS= read -r dependencyPath; do
dependencyName=$(dirname "$dependencyPath")
dependencySha=$(sha256sum "$dependencyPath" | cut -c 1-64)
cat <<EOF
- type: file
dest: .m2/repository/${dependencyName}
url: https://repo.maven.apache.org/maven2/${dependencyPath}
sha256: ${dependencySha}
only-arches: [${{ matrix.variant.arch }}]
EOF
done < maven-dependency-files-javafx.txt
) > javafx-maven-dependencies-${{ matrix.variant.arch }}.yaml
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: maven-sources-${{ matrix.variant.arch }}
if-no-files-found: error
path: |
maven-dependencies.yaml
javafx-maven-dependencies-${{ matrix.variant.arch }}.yaml
verify-maven-sources:
name: Verify maven sources
runs-on: ubuntu-latest
needs: [build-flatpak]
permissions:
contents: none
steps:
- name: Download updated maven aarch64 dependencies
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: maven-sources-aarch64
path: mvn-src-aarch64
- name: Download updated maven x86_64 dependencies
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: maven-sources-x86_64
path: mvn-src-x64
- name: Verify arch independent maven dependencies
run: cmp --silent mvn-src-aarch64/maven-dependencies.yaml mvn-src-x64/maven-dependencies.yaml
create-pr:
name: Create PR for flathub
runs-on: ubuntu-latest
needs: [get-version, verify-maven-sources]
if: (github.event_name == 'workflow_dispatch' && inputs.create-pr ) || (github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable')
permissions:
contents: write
env:
TARBALL_URL: 'https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name || inputs.src-tag }}.tar.gz'
steps:
- name: Check that input "src-tag" is actually a tag
if: github.event_name == 'workflow_dispatch'
run: |
if [ -z "$SRC_TAG" ]; then
echo '::error::Input "src-tag" must be set to create a Flathub PR'
exit 1
fi
env:
SRC_TAG: ${{ inputs.src-tag }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: flathub/org.cryptomator.Cryptomator
submodules: true #TODO: Update submodule!
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Checkout release branch
run: |
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
path: cryptomator
- name: Download source tarball and compute checksum
id: sha512
run: |
curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" ${TARBALL_URL} --output cryptomator.tar.gz
TARBALL_SHA512=$(sha512sum cryptomator.tar.gz | cut -d ' ' -f1)
echo "value=${TARBALL_SHA512}" >> "$GITHUB_OUTPUT"
- name: Download updated maven aarch64 dependencies
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: maven-sources-aarch64
path: mvn-src-aarch64
- name: Download updated maven x86_64 dependencies
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: maven-sources-x86_64
path: mvn-src-x64
- name: Determine revision
id: revision
run: |
CURRENT_VERSION="$(yq '(.modules[] | select(.name == "cryptomator") | .build-options.env.VERSION)' org.cryptomator.Cryptomator.yaml)"
CURRENT_REVISION="$(yq '(.modules[] | select(.name == "cryptomator") | .build-options.env.REVISION_NO)' org.cryptomator.Cryptomator.yaml)"
if [[ "$CURRENT_VERSION" == "$TARGET_VERSION" && "$CURRENT_REVISION" =~ ^[0-9]+$ ]]; then
NEXT_REVISION=$((CURRENT_REVISION + 1))
else
NEXT_REVISION=1
fi
echo "value=${NEXT_REVISION}" >> "$GITHUB_OUTPUT"
env:
TARGET_VERSION: ${{ needs.get-version.outputs.semVerStr }}
- name: Update build files
run: |
cp -r -f cryptomator/dist/linux/flatpak/* .
cp -r -f mvn-src-x64/* .
cp -r -f mvn-src-aarch64/* .
envsubst '$FLATPAK_VERSION $FLATPAK_REVISION $CRYPTOMATOR_SOURCE' < org.cryptomator.Cryptomator.TEMPLATE.yaml > org.cryptomator.Cryptomator.yaml
yq -i 'del(.modules[] | select(.name == "cryptomator") | .build-options.build-args)' org.cryptomator.Cryptomator.yaml
yq -i '(.modules[] | select(.name == "cryptomator") | .sources) += ["maven-dependencies.yaml", "javafx-maven-dependencies-x86_64.yaml", "javafx-maven-dependencies-aarch64.yaml"]' org.cryptomator.Cryptomator.yaml
env:
FLATPAK_VERSION: ${{ needs.get-version.outputs.semVerNum }}
FLATPAK_REVISION: ${{ steps.revision.outputs.value}}
CRYPTOMATOR_SOURCE: |-
type: archive
sha512: ${{steps.sha512.outputs.value}}
url: ${{ env.TARBALL_URL }}
- name: Commit and push
run: |
git config user.name "cryptobot"
git config user.email "cryptobot@users.noreply.github.com"
git config push.autoSetupRemote true
git stage org.cryptomator.Cryptomator.yaml maven-dependencies.yaml javafx-maven-dependencies-aarch64.yaml javafx-maven-dependencies-x86_64.yaml
git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}"
git push
- name: Create pull request
id: create-pr
run: |
printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md
PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
echo "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
if: github.event_name == 'release'
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: ''
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "Flathub release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.FLATHUB_PR_URL }}|PR> on how to proceed."
SLACK_FOOTER: ''
MSG_MINIMAL: true

View File

@@ -3,6 +3,8 @@ name: Build Arch package
on:
release:
types: [published]
schedule:
- cron: '0 21 20 * *'
workflow_dispatch:
inputs:
version:
@@ -130,7 +132,6 @@ jobs:
- name: Determine pkgrel
id: pkgrel
run: |
TARGET_VERSION='${{ needs.get-version.outputs.semVerStr }}'
CURRENT_VERSION="$(sed -nE 's/^pkgver=(.*)$/\1/p' PKGBUILD | head -n1)"
CURRENT_REL="$(sed -nE 's/^pkgrel=([0-9]+).*$/\1/p' PKGBUILD | head -n1)"
@@ -141,11 +142,11 @@ jobs:
fi
echo "value=${NEXT_REL}" >> "$GITHUB_OUTPUT"
echo "dist-version=${VERSION}-${NEXT_REL}" >> "$GITHUB_OUTPUT"
echo "dist-version=${TARGET_VERSION}-${NEXT_REL}" >> "$GITHUB_OUTPUT"
env:
VERSION: ${{ needs.get-version.outputs.semVerStr }}
TARGET_VERSION: ${{ needs.get-version.outputs.semVerStr }}
- name: Download PKGBUILD template
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: pkgbuild-file
- name: Prepare PKGBUILD
@@ -191,10 +192,10 @@ jobs:
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON: ''
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "AUR release PR created for ${{ github.event.repository.name }} ${{ steps.pkgrel.outputs.dist-version }} ."
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed."
SLACK_FOOTER: false
SLACK_FOOTER: ''
MSG_MINIMAL: true

View File

@@ -9,13 +9,45 @@ name: Build macOS .dmg for x64
#######################################
on:
release:
types: [published]
schedule:
- cron: '0 20 20 * *'
workflow_call:
inputs:
semVerNum:
type: string
description: 'The Major.Minor.Patch part of the version'
required: true
revisionNum:
type: string
description: 'The revision number'
required: true
semVerSuffix:
type: string
description: 'The suffix of the version, including dash'
required: true
notarize:
description: 'Notarize'
default: true
type: boolean
upload-to-draft:
type: boolean
default: true
outputs:
sha256-dmg:
description: "SHA256 sum of the x64 dmg"
value: ${{ jobs.build.outputs.sha256sum}}
workflow_dispatch:
inputs:
version:
description: 'Version'
semVerNum:
description: 'The Major.Minor.Patch part of the version'
required: false
revisionNum:
description: 'The revision number'
required: false
semVerSuffix:
description: 'The suffix of the version, including dash'
required: false
default: '-SNAPSHOT'
notarize:
description: 'Notarize'
required: true
@@ -25,17 +57,17 @@ on:
env:
JAVA_DIST: 'temurin'
JAVA_VERSION: '25.0.2+10.0.LTS'
VERSION_NUM: ${{ inputs.semVerNum || '99.99.99'}}
REVISION_NUM: ${{ inputs.revisionNum || '0' }}
VERSION_SUFFIX: ${{ inputs.semVerSuffix || ''}}
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.version }}
build-arm:
build:
name: Build Cryptomator.app for ${{ matrix.output-suffix }}
runs-on: ${{ matrix.os }}
needs: [get-version]
outputs:
sha256sum: ${{ steps.sha256sum.outputs.value }}
strategy:
fail-fast: false
matrix:
@@ -77,7 +109,7 @@ jobs:
exit 1
fi
- name: Set version
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
run : mvn versions:set -DnewVersion="${VERSION_NUM}${VERSION_SUFFIX}"
- name: Run maven
run: mvn -B clean package -Pmac -DskipTests
- name: Patch target dir
@@ -117,8 +149,8 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2025 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}"
--copyright "(C) 2016 - 2026 Skymatic GmbH"
--app-version "${VERSION_NUM}"
--java-options "--enable-preview"
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.mac"
--java-options "-Xss5m"
@@ -127,7 +159,7 @@ jobs:
--java-options "-Djava.net.useSystemProxies=true"
--java-options "-Dapple.awt.enableTemplateImages=true"
--java-options "-Dsun.java2d.metal=true"
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
--java-options "-Dcryptomator.appVersion=\"${VERSION_NUM}${VERSION_SUFFIX}\""
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\""
--java-options "-Dcryptomator.logDir=\"@{userhome}/Library/Logs/Cryptomator\""
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/Library/Application Support/Cryptomator/settings.json\""
@@ -137,7 +169,7 @@ jobs:
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Library/Application Support/Cryptomator/mnt\""
--java-options "-Dcryptomator.showTrayIcon=true"
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism"
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NUM}\""
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
--mac-package-identifier org.cryptomator
--resource-dir dist/mac/resources
@@ -146,12 +178,10 @@ jobs:
mv appdir/Cryptomator.app Cryptomator.app
mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/
cp dist/mac/resources/Assets.car Cryptomator.app/Contents/Resources/
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NUM}|g" Cryptomator.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NUM}|g" Cryptomator.app/Contents/Info.plist
echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile
env:
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
- name: Generate license for dmg
run: >
@@ -240,16 +270,14 @@ jobs:
--eula "dist/mac/dmg/resources/license.rtf"
--icon ".background" 128 758
--icon ".VolumeIcon.icns" 512 758
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
env:
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
Cryptomator-${VERSION_NUM}-${{ matrix.output-suffix }}.dmg dmg
- name: Codesign .dmg
run: |
codesign -s ${CODESIGN_IDENTITY} --timestamp Cryptomator-*.dmg
env:
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
- name: Notarize .dmg
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
if: inputs.notarize || github.event_name == 'schedule'
uses: cocoalibs/xcode-notarization-action@5cf433d494b6fa26504b574c591f4dd120388846 # v1.0.3
with:
app-path: 'Cryptomator-*.dmg'
@@ -257,8 +285,12 @@ jobs:
password: ${{ secrets.MACOS_NOTARIZATION_PW }}
team-id: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}
xcode-path: '/Applications/Xcode_16.app'
- id: sha256sum
run: |
read -ra CMD_OUTPUT < <(shasum -a256 Cryptomator-*.dmg)
echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT
- name: Add possible alpha/beta tags to installer name
run: mv Cryptomator-*.dmg Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.output-suffix }}.dmg
run: mv Cryptomator-*.dmg "Cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.output-suffix }}.dmg"
- name: Create detached GPG signature with key 615D449FE6E6A235
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
@@ -279,9 +311,10 @@ jobs:
Cryptomator-*.asc
if-no-files-found: error
- name: Publish dmg on GitHub Releases
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
if: inputs.upload-to-draft
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
with:
draft: true
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
files: |

View File

@@ -1,13 +1,45 @@
name: Build macOS .dmg for arm64
on:
release:
types: [published]
schedule:
- cron: '0 20 20 * *'
workflow_call:
inputs:
semVerNum:
type: string
description: 'The Major.Minor.Patch part of the version'
required: true
revisionNum:
type: string
description: 'The revision number'
required: true
semVerSuffix:
type: string
description: 'The suffix of the version, including dash'
required: true
notarize:
description: 'Notarize'
default: true
type: boolean
upload-to-draft:
type: boolean
default: true
outputs:
sha256-dmg:
description: "SHA256 sum of the arm64 dmg"
value: ${{ jobs.build.outputs.sha256sum}}
workflow_dispatch:
inputs:
version:
description: 'Version'
semVerNum:
description: 'The Major.Minor.Patch part of the version'
required: false
revisionNum:
description: 'The revision number'
required: false
semVerSuffix:
description: 'The suffix of the version, including dash'
required: false
default: '-SNAPSHOT'
notarize:
description: 'Notarize'
required: true
@@ -23,17 +55,17 @@ on:
env:
JAVA_DIST: 'temurin'
JAVA_VERSION: '25.0.2+10.0.LTS'
VERSION_NUM: ${{ inputs.semVerNum || '99.99.99'}}
REVISION_NUM: ${{ inputs.revisionNum || '0' }}
VERSION_SUFFIX: ${{ inputs.semVerSuffix || ''}}
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.version }}
build:
name: Build Cryptomator.app for ${{ matrix.output-suffix }}
runs-on: ${{ matrix.os }}
needs: [get-version]
outputs:
sha256sum: ${{ steps.sha256sum.outputs.value }}
strategy:
fail-fast: false
matrix:
@@ -75,7 +107,7 @@ jobs:
exit 1
fi
- name: Set version
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
run : mvn versions:set -DnewVersion="${VERSION_NUM}${VERSION_SUFFIX}"
- name: Run maven
run: mvn -B clean package -Pmac -DskipTests
- name: Patch target dir
@@ -115,8 +147,8 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2025 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}"
--copyright "(C) 2016 - 2026 Skymatic GmbH"
--app-version "${VERSION_NUM}"
--java-options "--enable-preview"
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.mac"
--java-options "-Xss5m"
@@ -125,7 +157,7 @@ jobs:
--java-options "-Djava.net.useSystemProxies=true"
--java-options "-Dapple.awt.enableTemplateImages=true"
--java-options "-Dsun.java2d.metal=true"
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
--java-options "-Dcryptomator.appVersion=\"${VERSION_NUM}${VERSION_SUFFIX}\""
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\""
--java-options "-Dcryptomator.logDir=\"@{userhome}/Library/Logs/Cryptomator\""
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/Library/Application Support/Cryptomator/settings.json\""
@@ -135,7 +167,7 @@ jobs:
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Library/Application Support/Cryptomator/mnt\""
--java-options "-Dcryptomator.showTrayIcon=true"
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism"
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NUM}\""
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log"
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
--mac-package-identifier org.cryptomator
@@ -145,12 +177,10 @@ jobs:
mv appdir/Cryptomator.app Cryptomator.app
mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/
cp dist/mac/resources/Assets.car Cryptomator.app/Contents/Resources/
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NUM}|g" Cryptomator.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NUM}|g" Cryptomator.app/Contents/Info.plist
echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile
env:
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
- name: Generate license for dmg
run: >
@@ -239,16 +269,14 @@ jobs:
--eula "dist/mac/dmg/resources/license.rtf"
--icon ".background" 128 758
--icon ".VolumeIcon.icns" 512 758
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
env:
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
Cryptomator-${VERSION_NUM}-${{ matrix.output-suffix }}.dmg dmg
- name: Codesign .dmg
run: |
codesign -s ${CODESIGN_IDENTITY} --timestamp Cryptomator-*.dmg
env:
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
- name: Notarize .dmg
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
if: inputs.notarize || github.event_name == 'schedule'
uses: cocoalibs/xcode-notarization-action@5cf433d494b6fa26504b574c591f4dd120388846 # v1.0.3
with:
app-path: 'Cryptomator-*.dmg'
@@ -256,8 +284,12 @@ jobs:
password: ${{ secrets.MACOS_NOTARIZATION_PW }}
team-id: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}
xcode-path: '/Applications/Xcode_16.app'
- id: sha256sum
run: |
read -ra CMD_OUTPUT < <(shasum -a256 Cryptomator-*.dmg)
echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT
- name: Add possible alpha/beta tags to installer name
run: mv Cryptomator-*.dmg Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.output-suffix }}.dmg
run: mv Cryptomator-*.dmg "Cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.output-suffix }}.dmg"
- name: Create detached GPG signature with key 615D449FE6E6A235
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
@@ -278,9 +310,10 @@ jobs:
Cryptomator-*.asc
if-no-files-found: error
- name: Publish dmg on GitHub Releases
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
if: inputs.upload-to-draft
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
with:
draft: true
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
files: |

View File

@@ -7,7 +7,7 @@ on:
jobs:
no-response:
runs-on: ubuntu-latest
runs-on: ubuntu-slim
permissions:
issues: write
pull-requests: write

View File

@@ -5,35 +5,141 @@ on:
types: [published]
jobs:
get-version:
runs-on: ubuntu-latest
notify:
runs-on: ubuntu-slim
steps:
- name: Download source tarball
run: |
curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
- name: Sign source tarball with key 615D449FE6E6A235
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.tar.gz
- name: Notify about DEB build
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
- name: Publish asc on GitHub Releases
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
files: |
cryptomator-*.tar.gz.asc
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: ''
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "Release ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published."
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/debian.yml|build deb Package>."
SLACK_FOOTER: ''
MSG_MINIMAL: true
- name: Notify about latest-version update
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: ''
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "Requiring version check source update for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }}."
SLACK_MESSAGE: 'Check S3 bucket for <https://static.cryptomator.org/desktop/latest-version.json|latest-version.json>.'
SLACK_FOOTER: ''
MSG_MINIMAL: true
get-asset-urls:
name: Get release asset URLs
runs-on: ubuntu-slim
outputs:
is-windows-release: ${{ steps.urls.outputs.urls-present }}
msi-url: ${{ steps.urls.outputs.msi }}
exe-url: ${{ steps.urls.outputs.exe }}
steps:
- name: Extract MSI and EXE download URLs
id: urls
run: |
MSI_URL=$(jq -r '[.[] | select(.name | endswith("-x64.msi"))][0].browser_download_url // "null"' <<< "$RELEASE_ASSETS")
EXE_URL=$(jq -r '[.[] | select(.name | endswith("-x64.exe"))][0].browser_download_url // "null"' <<< "$RELEASE_ASSETS")
if [[ "$MSI_URL" == "null" || -z "$MSI_URL" || "$EXE_URL" == "null" || -z "$EXE_URL" ]]; then
echo "urls-present=false" >> $GITHUB_OUTPUT
else
echo "urls-present=true" >> $GITHUB_OUTPUT
echo "msi=${MSI_URL}" >> $GITHUB_OUTPUT
echo "exe=${EXE_URL}" >> $GITHUB_OUTPUT
fi
env:
RELEASE_ASSETS: ${{ toJson(github.event.release.assets) }}
allowlist-msi-x64:
needs: [get-asset-urls]
if: needs.get-asset-urls.outputs.is-windows-release == 'true'
uses: ./.github/workflows/av-whitelist.yml
with:
url: ${{ needs.get-asset-urls.outputs.msi-url }}
secrets: inherit
allowlist-exe-x64:
needs: [get-asset-urls, allowlist-msi-x64]
if: needs.get-asset-urls.outputs.is-windows-release == 'true'
uses: ./.github/workflows/av-whitelist.yml
with:
url: ${{ needs.get-asset-urls.outputs.exe-url }}
secrets: inherit
check-release:
name: Analyzes the release for certain properties
runs-on: ubuntu-slim
outputs:
release-kind: ${{steps.determine-kind.outputs.value}} # Possible values are [alpha, beta, rc, stable, unknown]
steps:
- id: determine-kind
run: |
SEM_VER_NUM=$(echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/')
SEM_VER_SUFFIX="${SEM_VER_STR#"$SEM_VER_NUM"}"
TYPE="unknown"
if [[ -z $SEM_VER_SUFFIX ]]; then
TYPE="stable"
elif [[ $SEM_VER_SUFFIX =~ -alpha[1-9]+$ ]]; then
TYPE="alpha"
elif [[ $SEM_VER_SUFFIX =~ -beta[1-9]+$ ]]; then
TYPE="beta"
elif [[ $SEM_VER_SUFFIX =~ -rc[1-9]+$ ]]; then
TYPE="rc"
fi
echo "value=${TYPE}" >> $GITHUB_OUTPUT
env:
SEM_VER_STR: ${{ github.event.release.tag_name }}
notify-winget:
name: Notify for winget-release
if: needs.get-asset-urls.outputs.is-windows-release == 'true' && needs.check-release.outputs.release-kind == 'stable'
needs: [check-release, get-asset-urls]
runs-on: ubuntu-slim
steps:
- name: Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON: ''
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "Release ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published."
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/debian.yml|build deb Package>."
SLACK_FOOTER: false
MSG_MINIMAL: true
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/winget.yml|release to winget>."
SLACK_FOOTER: ''
MSG_MINIMAL: true
trigger-website-update:
needs: [check-release]
runs-on: ubuntu-slim
if: needs.check-release.outputs.release-kind == 'stable'
steps:
- name: Start website update workflow
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1
with:
event-type: desktop-release
token: ${{ secrets.CRYPTOBOT_WORKFLOW_DISPATCH_TOKEN }}
repository: cryptomator/cryptomator.github.io
client-payload: '{ "version": "${{ github.event.release.tag_name }}", "release": ${{ toJson(github.event.release.assets) }} }'
trigger-docs-update:
needs: [check-release, get-asset-urls]
runs-on: ubuntu-slim
if: needs.get-asset-urls.outputs.is-windows-release == 'true' && needs.check-release.outputs.release-kind == 'stable'
steps:
- name: Start docs update workflow
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1
with:
event-type: desktop-release
token: ${{ secrets.CRYPTOBOT_WORKFLOW_DISPATCH_TOKEN }}
repository: cryptomator/docs
client-payload: '{ "version": "${{ github.event.release.tag_name }}", "release": ${{ toJson(github.event.release.assets) }} }'

View File

@@ -50,7 +50,7 @@ jobs:
exit 1
fi
- name: Cache NVD DB
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ~/.m2/repository/org/owasp/dependency-check-data/
key: dependency-check-${{ github.run_id }}

View File

@@ -7,7 +7,7 @@ on:
jobs:
stale:
runs-on: ubuntu-latest
runs-on: ubuntu-slim
permissions:
issues: write
pull-requests: write

View File

@@ -1,13 +1,48 @@
name: Build Windows Installer
on:
release:
types: [published]
schedule:
- cron: '0 19 20 * *'
workflow_call:
inputs:
semVerNum:
type: string
description: 'The Major.Minor.Patch part of the version'
required: true
revisionNum:
type: string
description: 'The revision number'
required: true
semVerSuffix:
type: string
description: 'The suffix of the version, including dash'
required: true
sign:
description: 'Sign binaries'
default: true
type: boolean
upload-to-draft:
type: boolean
default: true
outputs:
sha256-msi:
description: "SHA256 sum of the x64 msi"
value: ${{ jobs.build-msi.outputs.sha256sum}}
sha256-exe:
description: "SHA256 sum of the x64 exe"
value: ${{ jobs.build-exe.outputs.sha256sum}}
workflow_dispatch:
inputs:
version:
description: 'Version'
semVerNum:
description: 'The Major.Minor.Patch part of the version'
required: false
revisionNum:
description: 'The revision number'
required: false
semVerSuffix:
description: 'The suffix of the version, including dash'
required: false
default: '-SNAPSHOT'
sign:
description: 'Sign binaries'
required: false
@@ -22,6 +57,9 @@ on:
env:
VERSION_NUM: ${{ inputs.semVerNum || '99.99.99'}}
REVISION_NUM: ${{ inputs.revisionNum || '0' }}
VERSION_SUFFIX: ${{ inputs.semVerSuffix || ''}}
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_windows-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: '33d878dfac85590c4d77c518ed413e512d34a8479d90132b230a7ddd173576b3'
WINFSP_MSI: 'https://github.com/winfsp/winfsp/releases/download/v2.1/winfsp-2.1.25156.msi'
@@ -34,15 +72,11 @@ defaults:
shell: bash
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.version }}
build-msi:
name: Build .msi Installer
runs-on: ${{ matrix.os }}
needs: [ get-version ]
outputs:
sha256sum: ${{ steps.sha256sum.outputs.value }}
strategy:
matrix:
include:
@@ -94,7 +128,7 @@ jobs:
exit 1
fi
- name: Set version
run: mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
run: mvn versions:set -DnewVersion="${VERSION_NUM}${VERSION_SUFFIX}"
- name: Run maven
run: mvn -B clean package -Pwin -DskipTests
- name: Patch target dir
@@ -134,13 +168,13 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2025 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
--copyright "(C) 2016 - 2026 Skymatic GmbH"
--app-version "${VERSION_NUM}.${REVISION_NUM}"
--java-options "--enable-preview"
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.win,org.cryptomator.integrations.win"
--java-options "-Xss5m"
--java-options "-Xmx256m"
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
--java-options "-Dcryptomator.appVersion=\"${VERSION_NUM}${VERSION_SUFFIX}\""
--java-options "-Dfile.encoding=\"utf-8\""
--java-options "-Djava.net.useSystemProxies=true"
--java-options "-Dcryptomator.adminConfigPath=\"C:/ProgramData/Cryptomator/config.properties\""
@@ -151,7 +185,7 @@ jobs:
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Cryptomator\""
--java-options "-Dcryptomator.loopbackAlias=\"cryptomator-vault\""
--java-options "-Dcryptomator.showTrayIcon=true"
--java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\""
--java-options "-Dcryptomator.buildNumber=\"msi-${REVISION_NUM}\""
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json\""
--java-options "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=\"@{appdata}/Cryptomator/windowsHelloKeychain.json\""
@@ -193,7 +227,7 @@ jobs:
& $env:JAVA_HOME\bin\jmod.exe extract --dir jpackage-jmod "${env:JAVA_HOME}\jmods\jdk.jpackage.jmod"
Get-ChildItem -Recurse -Path "jpackage-jmod" -File wixhelper.dll | Select-Object -Last 1 | Copy-Item -Destination "appdir"
- name: Sign DLLs with Azure Trusted Signing
if: inputs.sign || github.event_name == 'release'
if: inputs.sign || github.event_name == 'schedule'
uses: ./.github/actions/win-sign-action
with:
base-dir: ${{ github.workspace }}\appdir
@@ -202,17 +236,6 @@ jobs:
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
client-id: ${{ secrets.AZURE_CLIENT_ID }}
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Sign DLLs with Actalis CodeSigner
if: inputs.sign || github.event_name == 'release'
uses: skymatic/workflows/.github/actions/win-sign-action@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # no specific version
with:
base-dir: 'appdir'
file-extensions: 'dll,exe,ps1'
recursive: true
sign-description: 'Cryptomator'
sign-url: 'https://cryptomator.org'
username: ${{ secrets.WIN_CODESIGN_USERNAME }}
password: ${{ secrets.WIN_CODESIGN_PW }}
- name: Replace DLLs inside jars with signed ones
shell: pwsh
run: |
@@ -248,8 +271,8 @@ jobs:
--dest installer
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2025 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
--copyright "(C) 2016 - 2026 Skymatic GmbH"
--app-version "${VERSION_NUM}.${REVISION_NUM}"
--win-menu
--win-dir-chooser
--win-shortcut-prompt
@@ -262,7 +285,7 @@ jobs:
JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
JP_WIXHELPER_DIR: ${{ github.workspace }}\appdir
- name: Sign MSI with Azure Trusted Signing
if: inputs.sign || github.event_name == 'release'
if: inputs.sign || github.event_name == 'schedule'
uses: ./.github/actions/win-sign-action
with:
base-dir: ${{ github.workspace }}\installer
@@ -271,8 +294,12 @@ jobs:
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
client-id: ${{ secrets.AZURE_CLIENT_ID }}
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- id: sha256sum
run: |
read -ra CMD_OUTPUT < <(sha256sum installer/Cryptomator-*.msi)
echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT
- name: Add possible alpha/beta tags and architecture to installer name
run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.arch }}.msi
run: mv installer/Cryptomator-*.msi "Cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.arch }}.msi"
- name: Create detached GPG signature with key 615D449FE6E6A235
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
@@ -292,7 +319,9 @@ jobs:
build-exe:
name: Build .exe installer
runs-on: ${{ matrix.os }}
needs: [ get-version, build-msi ]
needs: [ build-msi ]
outputs:
sha256sum: ${{ steps.sha256sum.outputs.value }}
strategy:
matrix:
include:
@@ -312,7 +341,7 @@ jobs:
env:
WIX_VERSION: ${{ env.WIX_VERSION }}
- name: Download .msi
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: msi-${{ matrix.arch }}
path: dist/win/bundle/resources
@@ -339,10 +368,10 @@ jobs:
shell: pwsh
- name: Download WinFsp
run: |
curl --silent --fail-with-body --proto "=https" -L ${{ env.WINFSP_MSI }} --output $env:WINFSP_PATH
$computedHash = (Get-FileHash -Path $env:WINFSP_PATH -Algorithm SHA256).Hash.ToLower()
if ($computedHash -ne "${{ env.WINFSP_MSI_HASH }}") {
throw "Checksum mismatch for $env:WINFSP_PATH (expected ${{ env.WINFSP_MSI_HASH }}, got $computedHash)."
curl --silent --fail-with-body --proto "=https" -L "$env:WINFSP_MSI" --output $env:WINFSP_PATH
$computedHash = (Get-FileHash -Path "$env:WINFSP_PATH" -Algorithm SHA256).Hash.ToLower()
if ($computedHash -ne "$env:WINFSP_MSI_HASH") {
throw "Checksum mismatch for ${env:WINFSP_PATH} (expected ${env:WINFSP_MSI_HASH}, got $computedHash)."
}
env:
WINFSP_PATH: 'dist/win/bundle/resources/winfsp.msi'
@@ -356,21 +385,22 @@ jobs:
run: >
wix build
-define BundleName="Cryptomator"
-define BundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
-define BundleVersion="${VERSION_NUM}.${REVISION_NUM}"
-define BundleVendor="Skymatic GmbH"
-define BundleCopyright="(C) 2016 - 2025 Skymatic GmbH"
-define BundleCopyright="(C) 2016 - 2026 Skymatic GmbH"
-define AboutUrl="https://cryptomator.org"
-define HelpUrl="https://cryptomator.org/contact"
-define UpdateUrl="https://cryptomator.org/downloads/"
-ext "WixToolset.Util.wixext"
-ext "WixToolset.BootstrapperApplications.wixext"
./bundle/bundleWithWinfsp.wxs
-out "../../installer/unsigned/Cryptomator-Installer.exe"
-out "../../installer/Cryptomator-Installer.exe"
- name: Detach burn engine in preparation to sign
if: inputs.sign || github.event_name == 'schedule'
run: >
wix burn detach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe
wix burn detach installer/Cryptomator-Installer.exe -engine tmp/engine.exe
- name: Sign WiX burn engine with Azure Trusted Signing
if: inputs.sign || github.event_name == 'release'
if: inputs.sign || github.event_name == 'schedule'
uses: ./.github/actions/win-sign-action
with:
base-dir: ${{ github.workspace }}\tmp
@@ -380,21 +410,14 @@ jobs:
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
client-id: ${{ secrets.AZURE_CLIENT_ID }}
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Sign burn engine with Actalis CodeSigner
if: inputs.sign || github.event_name == 'release'
uses: skymatic/workflows/.github/actions/win-sign-action@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # no specific version
with:
base-dir: 'tmp'
file-extensions: 'exe'
sign-description: 'Cryptomator Bundle Installer'
sign-url: 'https://cryptomator.org'
username: ${{ secrets.WIN_CODESIGN_USERNAME }}
password: ${{ secrets.WIN_CODESIGN_PW }}
- name: Reattach signed burn engine to installer
run: >
wix burn reattach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe
if: inputs.sign || github.event_name == 'schedule'
shell: pwsh
run: |
Move-Item -Path installer/Cryptomator-Installer.exe -Destination tmp/Cryptomator-Installer.exe
wix burn reattach tmp/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe
- name: Sign EXE installer with Azure Trusted Signing
if: inputs.sign || github.event_name == 'release'
if: inputs.sign || github.event_name == 'schedule'
uses: ./.github/actions/win-sign-action
with:
base-dir: ${{ github.workspace }}\installer
@@ -404,18 +427,12 @@ jobs:
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
client-id: ${{ secrets.AZURE_CLIENT_ID }}
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Sign installer with Actalis CodeSigner
if: inputs.sign || github.event_name == 'release'
uses: skymatic/workflows/.github/actions/win-sign-action@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # no specific version
with:
base-dir: 'installer'
file-extensions: 'exe'
sign-description: 'Cryptomator Bundle Installer'
sign-url: 'https://cryptomator.org'
username: ${{ secrets.WIN_CODESIGN_USERNAME }}
password: ${{ secrets.WIN_CODESIGN_PW }}
- id: sha256sum
run: |
read -ra CMD_OUTPUT < <(sha256sum installer/Cryptomator-*.exe)
echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT
- name: Add possible alpha/beta tags to installer name
run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.executable-suffix }}.exe
run: mv installer/Cryptomator-Installer.exe "Cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.executable-suffix }}.exe"
- name: Create detached GPG signature with key 615D449FE6E6A235
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
@@ -434,58 +451,22 @@ jobs:
publish:
name: Publish installers to the github release
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
if: inputs.upload-to-draft
runs-on: ubuntu-latest
needs: [ build-msi, build-exe ]
outputs:
download-url-msi-x64: ${{ fromJSON(steps.publish.outputs.assets)[0].browser_download_url }}
download-url-exe-x64: ${{ fromJSON(steps.publish.outputs.assets)[2].browser_download_url }}
steps:
- name: Download installers
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
merge-multiple: true
- name: Publish installers on GitHub Releases
id: publish
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
with:
draft: true
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
# do not change ordering of filelist, required for correct job output
files: |
*x64.msi
*x64.exe
*.asc
allowlist-msi-x64:
uses: ./.github/workflows/av-whitelist.yml
needs: [ publish ]
with:
url: ${{ needs.publish.outputs.download-url-msi-x64 }}
secrets: inherit
allowlist-exe-x64:
uses: ./.github/workflows/av-whitelist.yml
needs: [ publish, allowlist-msi-x64 ]
with:
url: ${{ needs.publish.outputs.download-url-exe-x64 }}
secrets: inherit
notify-winget:
name: Notify for winget-release
if: needs.get-version.outputs.versionType == 'stable'
needs: [publish, get-version]
runs-on: ubuntu-latest
steps:
- name: Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "MSI packages of ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published."
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/winget.yml| release them to winget>."
SLACK_FOOTER: false
MSG_MINIMAL: true

View File

@@ -18,7 +18,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Submit package
uses: vedantmgoyal2009/winget-releaser@19e706d4c9121098010096f9c495a70a7518b30f # no_specific_version
uses: vedantmgoyal2009/winget-releaser@7bd472be23763def6e16bd06cc8b1cdfab0e2fd5 # no_specific_version
with:
identifier: Cryptomator.Cryptomator
version: ${{ inputs.tag }}

View File

@@ -7,6 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
The changelog starts with version 1.19.0.
Changes to prior versions can be found on the [Github release page](https://github.com/cryptomator/cryptomator/releases).
## [Unreleased](https://github.com/cryptomator/cryptomator/compare/1.19.2...HEAD)
### Changed
* Refactored release pipeline to allow immutable releases ([#4205](https://github.com/cryptomator/cryptomator/pull/4205))
## [1.19.2](https://github.com/cryptomator/cryptomator/releases/1.19.2) - 2026-03-20
### Security

View File

@@ -82,7 +82,7 @@ ${JAVA_HOME}/bin/jpackage \
--vendor "Skymatic GmbH" \
--java-options "--enable-preview" \
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
--copyright "(C) 2016 - 2025 Skymatic GmbH" \
--copyright "(C) 2016 - 2026 Skymatic GmbH" \
--java-options "-Xss5m" \
--java-options "-Xmx256m" \
--app-version "${VERSION}.${REVISION_NO}" \

View File

@@ -46,7 +46,7 @@ override_dh_auto_build:
--vendor "Skymatic GmbH" \
--java-options "--enable-preview" \
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
--copyright "(C) 2016 - 2025 Skymatic GmbH" \
--copyright "(C) 2016 - 2026 Skymatic GmbH" \
--java-options "-Xss5m" \
--java-options "-Xmx256m" \
--java-options "-Dfile.encoding=\"utf-8\"" \

View File

@@ -0,0 +1,11 @@
#!/bin/sh
# based on https://gitlab.gnome.org/GNOME/gnome-builder/-/blob/main/build-aux/flatpak/fusermount-wrapper.sh
#
# Sandbox escape hatch to call fusermount3 on the host system
#
# * fusermount3 is required for mount and unmount
# * FUSE3 requires for mounting a socket for communication, its file descriptor id is given in the _FUSE_COMMFD variable
# * Forwarding fd 1 and fd 2 ensures to catch process output of the fuse process
# * watch-bus ensures when the flatpak exits, also this process is killed
exec flatpak-spawn --host --watch-bus --forward-fd=1 --forward-fd=2 --env=_FUSE_COMMFD=${_FUSE_COMMFD} --forward-fd=${_FUSE_COMMFD} fusermount3 "$@"

View File

@@ -0,0 +1,182 @@
app-id: org.cryptomator.Cryptomator
command: cryptomator
runtime: org.freedesktop.Platform
runtime-version: '25.08'
sdk: org.freedesktop.Sdk
separate-locales: false
finish-args:
# Required for FUSE, see https://github.com/flathub/org.cryptomator.Cryptomator/pull/68#issuecomment-1935136502
- --device=all
# Set the PATH environment variable in the application, as flatpak is resetting the shell's PATH
- --env=PATH=/app/bin/:/usr/bin/
# Allow filesystem access to the user's home dir
# Needed to manage vaults there
- --filesystem=home
# Reading system certificates
- --filesystem=host-etc:ro
# Allow access to the XDG data directory
# Needed to connect to KeePassXC's UNIX domain socket
- --filesystem=xdg-run/org.keepassxc.KeePassXC.BrowserServer
- --filesystem=xdg-run/app/org.keepassxc.KeePassXC/
# Share IPC namespace with the host, without it the X11 shared memory extension will not work
- --share=ipc
# Allow access to the network
- --share=network
# Show windows using X11
- --socket=x11
# Needed to reveal encrypted files
- --talk-name=org.freedesktop.FileManager1
# Run any command on the host
# Needed to spawn fusermount on the host
- --talk-name=org.freedesktop.Flatpak
# Allow desktop notifications
- --talk-name=org.freedesktop.Notifications
# Allow access to the GNOME secret service API and to talk to the GNOME keyring daemon
- --talk-name=org.freedesktop.secrets
- --talk-name=org.gnome.keyring
# Allow to talk to the KDE kwallet daemon
- --talk-name=org.kde.kwalletd5
- --talk-name=org.kde.kwalletd6
# Needed to talk to the gvfs daemons over D-Bus and list mounts using the GIO APIs
- --talk-name=org.gtk.vfs.*
# Allow access to appindicator icons
- --talk-name=org.ayatana
# Allow access to appindicator icons on KDE
- --talk-name=org.kde.StatusNotifierWatcher
cleanup:
- /include
- /lib/pkgconfig
modules:
- shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json
- name: libfuse
buildsystem: meson
config-opts:
- -Dexamples=false
- -Dinitscriptdir=
- -Duseroot=false
- -Dtests=false
# don't install rules on the host
- -Dudevrulesdir=/tmp/
sources:
- type: archive
url: https://github.com/libfuse/libfuse/releases/download/fuse-3.16.2/fuse-3.16.2.tar.gz
sha256: f797055d9296b275e981f5f62d4e32e089614fc253d1ef2985851025b8a0ce87
x-checker-data:
type: anitya
project-id: 861
url-template: https://github.com/libfuse/libfuse/releases/download/fuse-$version/fuse-$version.tar.gz
versions: {<: '3.17.0'}
- name: host-command-wrapper
buildsystem: simple
build-commands:
- install fusermount-wrapper.sh /app/bin/fusermount3
sources:
- type: file
path: build-aux/fusermount-wrapper.sh
- name: cryptomator
buildsystem: simple
build-options:
build-args:
- --share=network
env:
PATH: /app/bin:/usr/bin
MAVEN_OPTS: -Dmaven.repo.local=.m2/repository
JAVA_HOME: jdk
JMODS_PATH: jmods
VERSION: $FLATPAK_VERSION
REVISION_NO: '$FLATPAK_REVISION'
build-commands:
# Setup Java
- tar xvfz jdk.tar.gz --transform 's!^[^/]*!jdk!'
- mkdir jmods
- unzip -j openjfx.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods
# Setup Maven
- mkdir maven
- tar xf maven.tar.gz --strip-components=1 --exclude=jansi-native --directory=maven
# Build project
- maven/bin/mvn clean package -DskipTests -P"linux-$(uname -m)"
- cp target/cryptomator-*.jar target/mods
- cd target
- $JAVA_HOME/bin/jlink
--output runtime
--module-path $JMODS_PATH
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.crypto.ec,jdk.crypto.cryptoki,jdk.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler
--no-header-files
--no-man-pages
--strip-debug
--compress=zip-0
- $JAVA_HOME/bin/jpackage
--type app-image
--runtime-image runtime
--input target/libs
--module-path target/mods
--module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
--dest .
--name Cryptomator
--vendor 'Skymatic GmbH'
--copyright '(C) 2016 - 2026 Skymatic GmbH'
--java-options '--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator'
--java-options "--sun-misc-unsafe-memory-access=allow"
--java-options '-Xss5m'
--java-options '-Xmx256m'
--java-options '-Dfile.encoding='utf-8''
--java-options '-Djava.net.useSystemProxies=true'
--java-options "-Dcryptomator.appVersion='${VERSION}'"
--java-options "-Dcryptomator.buildNumber='flatpak-${REVISION_NO}'"
--java-options '-Dcryptomator.ipcSocketPath='@{userhome}/.config/Cryptomator/ipc.socket''
--java-options '-Dcryptomator.adminConfigPath='/run/host/etc/cryptomator/config.properties''
--java-options '-Dcryptomator.logDir='@{userhome}/.local/share/Cryptomator/logs''
--java-options '-Dcryptomator.mountPointsDir='@{userhome}/.local/share/Cryptomator/mnt''
--java-options '-Dcryptomator.pluginDir='@{userhome}/.local/share/Cryptomator/plugins''
--java-options '-Dcryptomator.p12Path='@{userhome}/.config/Cryptomator/key.p12''
--java-options '-Dcryptomator.settingsPath='@{userhome}/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json''
--java-options '-Dcryptomator.showTrayIcon=true'
--java-options '-Dcryptomator.updateMechanism=org.cryptomator.linux.update.FlatpakUpdater'
--java-options '-Dcryptomator.networking.truststore.p12Path='/run/host/etc/cryptomator/certs.p12''
--java-options '-Dcryptomator.hub.enableTrustOnFirstUse=true'
--app-version "${VERSION}.${REVISION_NO}"
--verbose
- cp -R Cryptomator /app/
- ln -s /app/Cryptomator/bin/Cryptomator /app/bin/cryptomator
- cp -R /app/lib/* /app/Cryptomator/lib/app/
- install -D -m0644 -t /app/share/applications/ dist/linux/common/org.cryptomator.Cryptomator.desktop
- install -D -m0644 -t /app/share/icons/hicolor/scalable/apps/ dist/linux/common/org.cryptomator.Cryptomator.svg
- install -D -m0644 -T dist/linux/common/org.cryptomator.Cryptomator.tray.svg /app/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-symbolic.svg
- install -D -m0644 -T dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg /app/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-unlocked-symbolic.svg
- install -D -m0644 -t /app/share/metainfo/ dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml
sources:
- $CRYPTOMATOR_SOURCE
- type: file
dest-filename: jdk.tar.gz
only-arches:
- x86_64
url: https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2%2B10/OpenJDK25U-jdk_x64_linux_hotspot_25.0.2_10.tar.gz
sha512: 29043fde119a031c2ca8d57aed445fedd9e7f74608fcdc7a809076ba84cfd1c31f08de2ecccf352e159fdcd1cae172395ed46363007552ff242057826c81ab3a
- type: file
dest-filename: jdk.tar.gz
only-arches:
- aarch64
url: https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2%2B10/OpenJDK25U-jdk_aarch64_linux_hotspot_25.0.2_10.tar.gz
sha512: f1d3ccec3e1f1bed9d632f14b9223709d6e5c2e0d922125d068870dd3016492a2ca8f08924d4a9d0dc5eb2159fa09efee366a748fd0093475baf29e5c70c781a
- type: file
dest-filename: openjfx.zip
only-arches:
- x86_64
url: https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-x64_bin-jmods.zip
sha512: 21f550217101c513f9eb1d7947eba30cb79618238e6539ce770e54e84b01574cdaeba40af602391145f163dd8e43e3794395467413152f13ffffeff948b0ca1b
- type: file
dest-filename: openjfx.zip
only-arches:
- aarch64
url: https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-aarch64_bin-jmods.zip
sha512: a9268409b3803e386490bf1319d0f0a14173cebe862c12254cd51b430ee0a297437d9e38d5ebeae0da8899be898b312b103330d09dcfd3e63c1e7d15f2f14311
- type: file
dest-filename: maven.tar.gz
url: https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.9.13/apache-maven-3.9.13-bin.tar.gz
sha512: d9ccd44ba2991586e359c29eb86780ae8ff4ec1b88b0b8af3af074803472690cf2017782a9c4401343c62cbcd056231db9612e1e551cbd9747c21746d732c015
x-checker-data:
type: anitya
project-id: 1894
stable-only: true
url-template: https://repo1.maven.org/maven2/org/apache/maven/apache-maven/$version/apache-maven-$version-bin.tar.gz
versions: {<: '4.0'}

View File

@@ -24,7 +24,7 @@ rm -rf runtime dmg *.app *.dmg
# set variables
APP_NAME="Cryptomator"
VENDOR="Skymatic GmbH"
COPYRIGHT_YEARS="2016 - 2025"
COPYRIGHT_YEARS="2016 - 2026"
PACKAGE_IDENTIFIER="org.cryptomator"
MAIN_JAR_GLOB="cryptomator-*.jar"
MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"

View File

@@ -4,15 +4,18 @@
:: This file must be located in the INSTALLDIR
set "LOOPBACK_ALIAS=%1"
set "ACTION=%2"
if "%ACTION%"=="" set "ACTION=install"
:: Log for debugging
echo LOOPBACK_ALIAS=%LOOPBACK_ALIAS%
echo ACTION=%ACTION%
:: Change to INSTALLDIR
cd %~dp0
:: Execute the PowerShell script
powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -File .\patchWebDAV.ps1^
-LoopbackAlias %LOOPBACK_ALIAS%
-LoopbackAlias %LOOPBACK_ALIAS% -Action %ACTION%
:: Return the exit code from PowerShell
exit /b %ERRORLEVEL%

View File

@@ -1,15 +1,17 @@
#Requires -RunAsAdministrator
Param(
[Parameter(Mandatory, HelpMessage="Please provide an alias for 127.0.0.1")][string] $LoopbackAlias
[Parameter(Mandatory, HelpMessage="Please provide an alias for 127.0.0.1")][string] $LoopbackAlias,
[string] $Action = "install"
)
New-Variable -Name "sysdir" -Value ([Environment]::SystemDirectory) -Option Constant -Scope Global
New-Variable -Name "hostsFile" -Value "$sysdir\drivers\etc\hosts" -Option Constant -Scope Global
# Adds an alias for 127.0.0.1 to the hosts file
function Add-AliasToHost {
param (
[string]$LoopbackAlias
)
$sysdir = [Environment]::SystemDirectory
$hostsFile = "$sysdir\drivers\etc\hosts"
$aliasLine = "127.0.0.1 $LoopbackAlias"
foreach ($line in Get-Content $hostsFile) {
@@ -18,9 +20,26 @@ function Add-AliasToHost {
}
}
Add-Content -Path $hostsFile -Encoding ascii -Value "`r`n$aliasLine"
$content = Get-Content $hostsFile
$content += "`r`n$aliasLine"
$content | Set-Content "$hostsFile.tmp" -Encoding ascii
Move-Item "$hostsFile.tmp" $hostsFile -Force
}
# Removes an alias for 127.0.0.1 from the hosts file
function Remove-AliasFromHost {
param (
[string]$LoopbackAlias
)
$aliasLine = "127.0.0.1 $LoopbackAlias"
$content = Get-Content $hostsFile
$newContent = $content | Where-Object { $_ -ne $aliasLine }
$newContent | Set-Content "$hostsFile.tmp" -Encoding ascii
Move-Item "$hostsFile.tmp" $hostsFile -Force
}
# Sets in the registry the webclient file size limit to the maximum value
function Set-WebDAVFileSizeLimit {
@@ -54,14 +73,20 @@ function Edit-ProviderOrder {
New-ItemProperty -Path $RegistryPath -Name $Name -Value $UpdatedOrder -PropertyType String -Force | Out-Null
}
if ($Action -eq "install") {
Add-AliasToHost $LoopbackAlias
Write-Output 'Ensured alias exists in hosts file'
Add-AliasToHost $LoopbackAlias
Write-Output 'Ensured alias exists in hosts file'
Set-WebDAVFileSizeLimit
Write-Output 'Set WebDAV file size limit'
Set-WebDAVFileSizeLimit
Write-Output 'Set WebDAV file size limit'
Edit-ProviderOrder
Write-Output 'Ensured correct provider order'
Edit-ProviderOrder
Write-Output 'Ensured correct provider order'
} elseif ($Action -eq "uninstall") {
Remove-AliasFromHost $LoopbackAlias
Write-Output 'Ensured alias removed from hosts file'
} else {
Write-Error "Invalid action: $Action. Only 'install' or 'uninstall' are valid."
}
exit 0

View File

@@ -158,9 +158,13 @@
<ns0:CustomAction Id="DisableUserConfig" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" DllEntry="WixQuietExec" Execute="deferred" Return="ignore" Impersonate="no"/>
<!-- WebDAV patches -->
<ns0:SetProperty Id="PatchWebDAV" Value="&quot;[INSTALLDIR]patchWebDAV.bat&quot; &quot;$(var.LoopbackAlias)&quot;" Sequence="execute" Before="PatchWebDAV" />
<ns0:SetProperty Id="PatchWebDAV" Value="&quot;[INSTALLDIR]patchWebDAV.bat&quot; &quot;$(var.LoopbackAlias)&quot; install" Sequence="execute" Before="PatchWebDAV" />
<ns0:CustomAction Id="PatchWebDAV" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" DllEntry="WixQuietExec" Execute="deferred" Return="ignore" Impersonate="no"/>
<!-- WebDAV patches (Uninstall) -->
<ns0:SetProperty Id="PatchWebDAVUninstall" Value="&quot;[INSTALLDIR]patchWebDAV.bat&quot; &quot;$(var.LoopbackAlias)&quot; uninstall" Sequence="execute" Before="PatchWebDAVUninstall" />
<ns0:CustomAction Id="PatchWebDAVUninstall" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" DllEntry="WixQuietExec" Execute="deferred" Return="ignore" Impersonate="no"/>
<!-- Update check configuration -->
<ns0:SetProperty Id="PatchUpdateCheck" Value="&quot;[INSTALLDIR]patchUpdateCheck.bat&quot; &quot;[DISABLEUPDATECHECK]&quot;" Sequence="execute" Before="PatchUpdateCheck" />
<ns0:CustomAction Id="PatchUpdateCheck" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" DllEntry="WixQuietExec64" Execute="deferred" Return="ignore" Impersonate="no"/>
@@ -214,9 +218,8 @@
<ns0:RemoveExistingProducts After="InstallValidate"/> <!-- Moved from CostInitialize, due to Wix4CloseApplications_* -->
<ns0:Custom Action="DisableUserConfig" After="InstallFiles" Condition="NOT (Installed AND (NOT REINSTALL) AND (NOT UPGRADINGPRODUCTCODE) AND REMOVE)"/>
<!-- Skip action on uninstall -->
<!-- TODO: don't skip action, but remove cryptomator alias from hosts file -->
<ns0:Custom Action="PatchWebDAV" After="DisableUserConfig" Condition="NOT (Installed AND (NOT REINSTALL) AND (NOT UPGRADINGPRODUCTCODE) AND REMOVE)"/>
<ns0:Custom Action="PatchWebDAVUninstall" Before="RemoveFiles" Condition="Installed AND (NOT REINSTALL) AND (NOT UPGRADINGPRODUCTCODE) AND REMOVE" />
<!-- Configure update check setting if property is provided -->
<ns0:Custom Action="PatchUpdateCheck" After="PatchWebDAV" Condition="DISABLEUPDATECHECK AND NOT (Installed AND (NOT REINSTALL) AND (NOT UPGRADINGPRODUCTCODE) AND REMOVE)"/>
</ns0:InstallExecuteSequence>
@@ -228,4 +231,4 @@
<ns0:WixVariable Id="WixUIBannerBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\banner.bmp" />
<ns0:WixVariable Id="WixUIDialogBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\background.bmp" />
</ns0:Package>
</ns0:Wix>
</ns0:Wix>

50
pom.xml
View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>cryptomator</artifactId>
<version>1.19.2</version>
<version>1.20.0-SNAPSHOT</version>
<name>Cryptomator Desktop App</name>
<organization>
@@ -527,11 +527,57 @@
</profile>
<profile>
<id>linux</id>
<id>linux-aarch64</id>
<activation>
<os>
<family>unix</family>
<name>Linux</name>
<arch>aarch64</arch>
</os>
<property>
<name>idea.version</name>
</property>
</activation>
<dependencies>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>integrations-linux</artifactId>
<version>${cryptomator.integrations.linux.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>${javafx.version}</version>
<classifier>linux-aarch64</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>${javafx.version}</version>
<classifier>linux-aarch64</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
<classifier>linux-aarch64</classifier>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
<classifier>linux-aarch64</classifier>
</dependency>
</dependencies>
</profile>
<profile>
<id>linux-x86_64</id>
<activation>
<os>
<family>unix</family>
<name>Linux</name>
<arch>amd64</arch>
</os>
<property>
<name>idea.version</name>

View File

@@ -58,8 +58,6 @@ public class DecryptFileNamesViewController implements FxController {
private final Stage window;
private final Vault vault;
private final ResourceBundle resourceBundle;
private final List<Path> initialList;
@FXML
public TableColumn<CipherAndCleartext, String> ciphertextColumn;
@FXML
@@ -68,12 +66,11 @@ public class DecryptFileNamesViewController implements FxController {
public TableView<CipherAndCleartext> cipherToCleartextTable;
@Inject
public DecryptFileNamesViewController(@DecryptNameWindow Stage window, @DecryptNameWindow Vault vault, @DecryptNameWindow List<Path> pathsToDecrypt, ResourceBundle resourceBundle) {
public DecryptFileNamesViewController(@DecryptNameWindow Stage window, @DecryptNameWindow Vault vault, ResourceBundle resourceBundle) {
this.window = window;
this.vault = vault;
this.resourceBundle = resourceBundle;
this.mapping = new SimpleListProperty<>(FXCollections.observableArrayList());
this.initialList = pathsToDecrypt;
}
@FXML
@@ -97,8 +94,7 @@ public class DecryptFileNamesViewController implements FxController {
});
cipherToCleartextTable.setOnDragDropped(event -> {
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
checkAndDecrypt(event.getDragboard().getFiles().stream().map(File::toPath).toList());
cipherToCleartextTable.setItems(mapping);
decrypt(event.getDragboard().getFiles().stream().map(File::toPath).toList());
}
});
cipherToCleartextTable.setOnDragExited(_ -> cipherToCleartextTable.setItems(mapping));
@@ -124,9 +120,7 @@ public class DecryptFileNamesViewController implements FxController {
});
}
});
if (!initialList.isEmpty()) {
checkAndDecrypt(initialList);
}
window.setOnHidden(_ -> mapping.clear());
}
private void copySingleCelltoClipboard() {
@@ -149,10 +143,18 @@ public class DecryptFileNamesViewController implements FxController {
fileChooser.setInitialDirectory(vault.getPath().toFile());
var ciphertextNodes = fileChooser.showOpenMultipleDialog(window);
if (ciphertextNodes != null) {
checkAndDecrypt(ciphertextNodes.stream().map(File::toPath).toList());
decrypt(ciphertextNodes.stream().map(File::toPath).toList());
}
}
public void decrypt(List<Path> pathsToDecrypt) {
if (pathsToDecrypt.isEmpty()) {
return;
}
checkAndDecrypt(pathsToDecrypt);
cipherToCleartextTable.setItems(mapping);
}
private void checkAndDecrypt(List<Path> pathsToDecrypt) {
mapping.clear();
//Assumption: All files are in the same directory

View File

@@ -28,23 +28,28 @@ public interface DecryptNameComponent {
@FxmlScene(FxmlFile.DECRYPTNAMES)
Lazy<Scene> decryptNamesView();
DecryptFileNamesViewController controller();
@DecryptNameWindow
Vault vault();
default void showDecryptFileNameWindow() {
default void showDecryptFileNameWindow(List<Path> pathsToDecrypt) {
Stage s = window();
s.setScene(decryptNamesView().get());
s.sizeToScene();
if (vault().isUnlocked()) {
controller().decrypt(pathsToDecrypt);
s.show();
s.requestFocus();
} else {
LOG.error("Aborted showing DecryptFileName window: vault state is not {}, but {}.", VaultState.Value.UNLOCKED, vault().getState());
s.close();
}
}
@Subcomponent.Factory
interface Factory {
DecryptNameComponent create(@BindsInstance @DecryptNameWindow Vault vault, @BindsInstance @Named("windowOwner") Stage owner, @BindsInstance @DecryptNameWindow List<Path> pathsToDecrypt);
DecryptNameComponent create(@BindsInstance @DecryptNameWindow Vault vault, @BindsInstance @Named("windowOwner") Stage owner);
}
}

View File

@@ -64,17 +64,6 @@ abstract class FxApplicationModule {
return builder.build();
}
@Provides
@FxApplicationScoped
static MainWindowComponent provideMainWindowComponent(MainWindowComponent.Builder builder) {
return builder.build();
}
@Provides
@FxApplicationScoped
static PreferencesComponent providePreferencesComponent(PreferencesComponent.Builder builder) {
return builder.build();
}
@Provides
@FxApplicationScoped
@@ -88,10 +77,4 @@ abstract class FxApplicationModule {
return factory.create();
}
@Provides
@FxApplicationScoped
static NotificationComponent provideNotificationComponent(NotificationComponent.Factory factory) {
return factory.create();
}
}

View File

@@ -39,6 +39,7 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutorService;
import java.util.function.Supplier;
@FxApplicationScoped
public class FxApplicationWindows {
@@ -47,15 +48,15 @@ public class FxApplicationWindows {
private final Stage primaryStage;
private final Optional<TrayIntegrationProvider> trayIntegration;
private final Lazy<MainWindowComponent> mainWindow;
private final Lazy<PreferencesComponent> preferencesWindow;
private final CachedLazy<MainWindowComponent> mainWindow;
private final CachedLazy<PreferencesComponent> preferencesWindow;
private final QuitComponent.Builder quitWindowBuilder;
private final UnlockComponent.Factory unlockWorkflowFactory;
private final UpdateReminderComponent.Factory updateReminderWindowFactory;
private final LockComponent.Factory lockWorkflowFactory;
private final ErrorComponent.Factory errorWindowFactory;
private final Lazy<EventViewComponent> eventViewWindow;
private final Lazy<NotificationComponent> notificationWindow;
private final CachedLazy<EventViewComponent> eventViewWindow;
private final CachedLazy<NotificationComponent> notificationWindow;
private final ExecutorService executor;
private final VaultOptionsComponent.Factory vaultOptionsWindow;
private final ShareVaultComponent.Factory shareVaultWindow;
@@ -65,8 +66,8 @@ public class FxApplicationWindows {
@Inject
public FxApplicationWindows(@PrimaryStage Stage primaryStage, //
Optional<TrayIntegrationProvider> trayIntegration, //
Lazy<MainWindowComponent> mainWindow, //
Lazy<PreferencesComponent> preferencesWindow, //
MainWindowComponent.Builder mainWindowBuilder, //
PreferencesComponent.Builder preferencesWindowBuilder, //
QuitComponent.Builder quitWindowBuilder, //
UnlockComponent.Factory unlockWorkflowFactory, //
UpdateReminderComponent.Factory updateReminderWindowFactory, //
@@ -74,21 +75,21 @@ public class FxApplicationWindows {
ErrorComponent.Factory errorWindowFactory, //
VaultOptionsComponent.Factory vaultOptionsWindow, //
ShareVaultComponent.Factory shareVaultWindow, //
Lazy<EventViewComponent> eventViewWindow, //
Lazy<NotificationComponent> notificationWindow,
EventViewComponent.Factory eventViewWindowFactory, //
NotificationComponent.Factory notificationWindowFactory, //
ExecutorService executor, //
Dialogs dialogs) {
this.primaryStage = primaryStage;
this.trayIntegration = trayIntegration;
this.mainWindow = mainWindow;
this.preferencesWindow = preferencesWindow;
this.mainWindow = new CachedLazy<>(mainWindowBuilder::build);
this.preferencesWindow = new CachedLazy<>(preferencesWindowBuilder::build);
this.quitWindowBuilder = quitWindowBuilder;
this.unlockWorkflowFactory = unlockWorkflowFactory;
this.updateReminderWindowFactory = updateReminderWindowFactory;
this.lockWorkflowFactory = lockWorkflowFactory;
this.errorWindowFactory = errorWindowFactory;
this.eventViewWindow = eventViewWindow;
this.notificationWindow = notificationWindow;
this.eventViewWindow = new CachedLazy<>(eventViewWindowFactory::create);
this.notificationWindow = new CachedLazy<>(notificationWindowFactory::create);
this.executor = executor;
this.vaultOptionsWindow = vaultOptionsWindow;
this.shareVaultWindow = shareVaultWindow;
@@ -218,4 +219,29 @@ public class FxApplicationWindows {
LOG.error("Failed to display stage", error);
}
}
private static class CachedLazy<T> implements Lazy<T> {
private final Supplier<T> supplier;
private volatile T instance = null;
public CachedLazy(Supplier<T> supplier) {
this.supplier = supplier;
}
@Override
public T get() {
T value = instance;
if (value == null) {
synchronized (this) {
value = instance;
if (value == null) {
value = supplier.get();
instance = value;
}
}
}
return instance;
}
}
}

View File

@@ -1,9 +1,8 @@
package org.cryptomator.ui.mainwindow;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.tobiasdiez.easybind.EasyBind;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Nullable;
@@ -58,6 +57,7 @@ public class VaultDetailUnlockedController implements FxController {
private final DecryptNameComponent.Factory decryptNameWindowFactory;
private final ResourceBundle resourceBundle;
private final LoadingCache<Vault, VaultStatisticsComponent> vaultStats;
private final LoadingCache<Vault, DecryptNameComponent> decryptNameWindows;
private final VaultStatisticsComponent.Builder vaultStatsBuilder;
private final ObservableValue<Boolean> accessibleViaPath;
private final ObservableValue<Boolean> accessibleViaUri;
@@ -89,7 +89,8 @@ public class VaultDetailUnlockedController implements FxController {
this.revealPathService = revealPathService;
this.decryptNameWindowFactory = decryptNameWindowFactory;
this.resourceBundle = resourceBundle;
this.vaultStats = CacheBuilder.newBuilder().weakValues().build(CacheLoader.from(this::buildVaultStats));
this.vaultStats = Caffeine.newBuilder().weakValues().build(this::buildVaultStats);
this.decryptNameWindows = Caffeine.newBuilder().weakValues().build(this::buildDecryptNameWindow);
this.vaultStatsBuilder = vaultStatsBuilder;
var mp = vault.flatMap(Vault::mountPointProperty);
this.accessibleViaPath = mp.map(m -> m instanceof Mountpoint.WithPath).orElse(false);
@@ -161,7 +162,7 @@ public class VaultDetailUnlockedController implements FxController {
}
private void showDecryptNameWindow(List<Path> pathsToDecrypt) {
decryptNameWindowFactory.create(vault.get(), mainWindow, pathsToDecrypt).showDecryptFileNameWindow();
decryptNameWindows.get(vault.get()).showDecryptFileNameWindow(pathsToDecrypt);
}
private boolean startsWithVaultAccessPoint(Path path) {
@@ -198,6 +199,10 @@ public class VaultDetailUnlockedController implements FxController {
return vaultStatsBuilder.vault(vault).build();
}
private DecryptNameComponent buildDecryptNameWindow(Vault vault) {
return decryptNameWindowFactory.create(vault, mainWindow);
}
@FXML
public void revealAccessLocation() {
vaultService.reveal(vault.get());
@@ -217,7 +222,7 @@ public class VaultDetailUnlockedController implements FxController {
@FXML
public void showVaultStatistics() {
vaultStats.getUnchecked(vault.get()).showVaultStatisticsWindow();
vaultStats.get(vault.get()).showVaultStatisticsWindow();
}
/* Getter/Setter */

View File

@@ -260,7 +260,7 @@ public class UpdatesPreferencesController implements FxController {
public boolean isProhibitUpdateWhileUnlocked() {
// If the result of the last update check was from the fallback mechanism, we don't need to show the warning
return !unlockedVaults.isEmpty() && !FallbackUpdateInfo.class.isInstance(updateChecker.getUpdate());
return !unlockedVaults.isEmpty() && updateChecker.isUpdateAvailable() && !FallbackUpdateInfo.class.isInstance(updateChecker.getUpdate());
}
public BooleanBinding prohibitUpdateWhileUnlockedProperty() {

View File

@@ -18,7 +18,10 @@ import java.net.URISyntaxException;
public class ShareVaultController implements FxController {
private static final String SCHEME_PREFIX = "hub+";
private static final String VISIT_HUB_URL = "https://cryptomator.org/hub/";
private static final String VISIT_HUB_URL = "https://cryptomator.org/hub/" //
+ "?utm_source=cryptomator-desktop" //
+ "&utm_medium=app" //
+ "&utm_campaign=share-vault";
private static final String BEST_PRACTICES_URL = "https://docs.cryptomator.org/security/best-practices/#sharing-of-vaults";
private final Stage window;

View File

@@ -22,7 +22,7 @@
</ImageView>
<VBox spacing="3" HBox.hgrow="ALWAYS" alignment="CENTER_LEFT">
<FormattedLabel styleClass="label-extra-large" format="Cryptomator %s" arg1="${controller.fullApplicationVersion}"/>
<Label text="© 2016 2025 Skymatic GmbH"/>
<Label text="© 2016 2026 Skymatic GmbH"/>
</VBox>
</HBox>

View File

@@ -9,90 +9,94 @@
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.vaultoptions.MountOptionsController"
spacing="6">
<fx:define>
<ToggleGroup fx:id="mountPointToggleGroup"/>
</fx:define>
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<HBox spacing="12" alignment="CENTER_LEFT">
<Label text="%vaultOptions.mount.volume.type" labelFor="$vaultVolumeTypeChoiceBox"/>
<ChoiceBox fx:id="vaultVolumeTypeChoiceBox"/>
<Hyperlink contentDisplay="GRAPHIC_ONLY" onAction="#openVolumePreferences" visible="${controller.defaultMountServiceSelected}" managed="${controller.defaultMountServiceSelected}" accessibleText="%vaultOptions.mount.info">
<graphic>
<FontAwesome5IconView glyph="COGS" styleClass="glyph-icon-muted"/>
</graphic>
<tooltip>
<Tooltip text="%vaultOptions.mount.info" showDelay="100ms"/>
</tooltip>
</Hyperlink>
<Hyperlink contentDisplay="GRAPHIC_ONLY" onAction="#openDocs" visible="${!controller.defaultMountServiceSelected}" managed="${!controller.defaultMountServiceSelected}" accessibleText="%preferences.volume.docsTooltip">
<graphic>
<FontAwesome5IconView glyph="QUESTION_CIRCLE" styleClass="glyph-icon-muted"/>
</graphic>
<tooltip>
<Tooltip text="%preferences.volume.docsTooltip" showDelay="100ms"/>
</tooltip>
</Hyperlink>
</HBox>
<Label styleClass="label-red" text="%vaultOptions.mount.volumeType.restartRequired" visible="${controller.selectedMountServiceRequiresRestart}" managed="${controller.selectedMountServiceRequiresRestart}"/>
<HBox spacing="12" alignment="CENTER_LEFT" visible="${controller.loopbackPortChangeable}" managed="${controller.loopbackPortChangeable}">
<Label text="%vaultOptions.mount.volume.tcp.port" labelFor="$vaultLoopbackPortField"/>
<NumericTextField fx:id="vaultLoopbackPortField"/>
<Button text="%generic.button.apply" fx:id="vaultLoopbackPortApplyButton" onAction="#doChangeLoopbackPort"/>
</HBox>
<CheckBox fx:id="readOnlyCheckbox" text="%vaultOptions.mount.readonly" visible="${controller.readOnlyOptionAllowed}" managed="${controller.readOnlyOptionAllowed}"/>
<VBox visible="${controller.mountFlagsSupported}" managed="${controller.mountFlagsSupported}">
<CheckBox fx:id="customMountFlagsCheckbox" text="%vaultOptions.mount.customMountFlags" onAction="#toggleUseCustomMountFlags"/>
<TextField fx:id="mountFlagsField" HBox.hgrow="ALWAYS" maxWidth="Infinity" accessibleText="%vaultOptions.mount.customMountFlags">
<VBox.margin>
<Insets left="24"/>
</VBox.margin>
</TextField>
</VBox>
<Label text="%vaultOptions.mount.mountPoint">
<VBox.margin>
<Insets top="9"/>
</VBox.margin>
</Label>
<RadioButton toggleGroup="${mountPointToggleGroup}" fx:id="mountPointAutoBtn" text="%vaultOptions.mount.mountPoint.auto"/>
<HBox spacing="6" visible="${controller.mountpointDriveLetterSupported}" managed="${controller.mountpointDriveLetterSupported}">
<RadioButton toggleGroup="${mountPointToggleGroup}" fx:id="mountPointDriveLetterBtn" text="%vaultOptions.mount.mountPoint.driveLetter"/>
<ChoiceBox fx:id="driveLetterSelection" disable="${!mountPointDriveLetterBtn.selected}" accessibleText="%vaultOptions.mount.mountPoint.driveLetter"/>
</HBox>
<VBox spacing="6" visible="${controller.mountpointDirSupported}" managed="${controller.mountpointDirSupported}">
<HBox spacing="6" alignment="CENTER_LEFT">
<RadioButton toggleGroup="${mountPointToggleGroup}" fx:id="mountPointDirBtn" text="%vaultOptions.mount.mountPoint.custom"/>
<Button text="%vaultOptions.mount.mountPoint.directoryPickerButton" onAction="#chooseCustomMountPoint" contentDisplay="LEFT" disable="${!mountPointDirBtn.selected}">
<ScrollPane xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.vaultoptions.MountOptionsController"
fitToWidth="true"
hbarPolicy="NEVER">
<VBox spacing="6">
<fx:define>
<ToggleGroup fx:id="mountPointToggleGroup"/>
</fx:define>
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<HBox spacing="12" alignment="CENTER_LEFT">
<Label text="%vaultOptions.mount.volume.type" labelFor="$vaultVolumeTypeChoiceBox"/>
<ChoiceBox fx:id="vaultVolumeTypeChoiceBox"/>
<Hyperlink contentDisplay="GRAPHIC_ONLY" onAction="#openVolumePreferences" visible="${controller.defaultMountServiceSelected}" managed="${controller.defaultMountServiceSelected}" accessibleText="%vaultOptions.mount.info">
<graphic>
<FontAwesome5IconView glyph="FOLDER_OPEN" glyphSize="15"/>
<FontAwesome5IconView glyph="COGS" styleClass="glyph-icon-muted"/>
</graphic>
</Button>
<tooltip>
<Tooltip text="%vaultOptions.mount.info" showDelay="100ms"/>
</tooltip>
</Hyperlink>
<Hyperlink contentDisplay="GRAPHIC_ONLY" onAction="#openDocs" visible="${!controller.defaultMountServiceSelected}" managed="${!controller.defaultMountServiceSelected}" accessibleText="%preferences.volume.docsTooltip">
<graphic>
<FontAwesome5IconView glyph="QUESTION_CIRCLE" styleClass="glyph-icon-muted"/>
</graphic>
<tooltip>
<Tooltip text="%preferences.volume.docsTooltip" showDelay="100ms"/>
</tooltip>
</Hyperlink>
</HBox>
<TextField fx:id="directoryPathField" text="${controller.directoryPath}" visible="${mountPointDirBtn.selected}" managed="${mountPointDirBtn.managed}" maxWidth="Infinity" editable="false" accessibleText="%vaultOptions.mount.mountPoint.custom">
<VBox.margin>
<Insets left="24"/>
</VBox.margin>
</TextField>
</VBox>
</children>
</VBox>
<Label styleClass="label-red" text="%vaultOptions.mount.volumeType.restartRequired" visible="${controller.selectedMountServiceRequiresRestart}" managed="${controller.selectedMountServiceRequiresRestart}"/>
<HBox spacing="12" alignment="CENTER_LEFT" visible="${controller.loopbackPortChangeable}" managed="${controller.loopbackPortChangeable}">
<Label text="%vaultOptions.mount.volume.tcp.port" labelFor="$vaultLoopbackPortField"/>
<NumericTextField fx:id="vaultLoopbackPortField"/>
<Button text="%generic.button.apply" fx:id="vaultLoopbackPortApplyButton" onAction="#doChangeLoopbackPort"/>
</HBox>
<CheckBox fx:id="readOnlyCheckbox" text="%vaultOptions.mount.readonly" visible="${controller.readOnlyOptionAllowed}" managed="${controller.readOnlyOptionAllowed}"/>
<VBox visible="${controller.mountFlagsSupported}" managed="${controller.mountFlagsSupported}">
<CheckBox fx:id="customMountFlagsCheckbox" text="%vaultOptions.mount.customMountFlags" onAction="#toggleUseCustomMountFlags"/>
<TextField fx:id="mountFlagsField" HBox.hgrow="ALWAYS" maxWidth="Infinity" accessibleText="%vaultOptions.mount.customMountFlags">
<VBox.margin>
<Insets left="24"/>
</VBox.margin>
</TextField>
</VBox>
<Label text="%vaultOptions.mount.mountPoint">
<VBox.margin>
<Insets top="9"/>
</VBox.margin>
</Label>
<RadioButton toggleGroup="${mountPointToggleGroup}" fx:id="mountPointAutoBtn" text="%vaultOptions.mount.mountPoint.auto"/>
<HBox spacing="6" visible="${controller.mountpointDriveLetterSupported}" managed="${controller.mountpointDriveLetterSupported}">
<RadioButton toggleGroup="${mountPointToggleGroup}" fx:id="mountPointDriveLetterBtn" text="%vaultOptions.mount.mountPoint.driveLetter"/>
<ChoiceBox fx:id="driveLetterSelection" disable="${!mountPointDriveLetterBtn.selected}" accessibleText="%vaultOptions.mount.mountPoint.driveLetter"/>
</HBox>
<VBox spacing="6" visible="${controller.mountpointDirSupported}" managed="${controller.mountpointDirSupported}">
<HBox spacing="6" alignment="CENTER_LEFT">
<RadioButton toggleGroup="${mountPointToggleGroup}" fx:id="mountPointDirBtn" text="%vaultOptions.mount.mountPoint.custom"/>
<Button text="%vaultOptions.mount.mountPoint.directoryPickerButton" onAction="#chooseCustomMountPoint" contentDisplay="LEFT" disable="${!mountPointDirBtn.selected}">
<graphic>
<FontAwesome5IconView glyph="FOLDER_OPEN" glyphSize="15"/>
</graphic>
</Button>
</HBox>
<TextField fx:id="directoryPathField" text="${controller.directoryPath}" visible="${mountPointDirBtn.selected}" managed="${mountPointDirBtn.managed}" maxWidth="Infinity" editable="false" accessibleText="%vaultOptions.mount.mountPoint.custom">
<VBox.margin>
<Insets left="24"/>
</VBox.margin>
</TextField>
</VBox>
</children>
</VBox>
</ScrollPane>