Compare commits

..

22 commits

Author SHA1 Message Date
jkarasti
e6380f793b Fix: Dangerzone installed using an msi built with WiX Toolset v3 is not uninstalled by an msi built with WiX Toolset v5
Workaround for an issue after upgrading from WiX Toolset v3 to v5 where the previous
version of Dangerzone is not uninstalled during the upgrade by checking if the older installation
exists in "C:\Program Files (x86)\Dangerzone".

Also handle a special case for Dangerzone 0.8.0 which allows choosing the install location
during install by checking if the registry key for it exists.

Note that this seems to allow installing Dangerzone 0.8.0 after installing Dangerzone from this branch.
In this case the installer errors until Dangerzone 0.8.0 is uninstalled again
2024-11-22 19:52:30 +02:00
JKarasti
ce85bde109 Change: Build a 64-bit installer 2024-11-20 21:27:31 +02:00
JKarasti
95239b5f88 Docs: Update documentation for WiX Toolset 5 2024-11-20 21:27:13 +02:00
JKarasti
32626b4b99 Change: Update the build-app.bat script to work with WiX Toolset v5
- WiX Toolset v3 used to validate the msi package by default. In v5 that has moved to a new command, so add a new validation step to the script.

- Also emove the step that uses `insignia.exe` to sign the Dangerzone.msi with the digital signatures from its external cab archives.

  In WiX Toolset v4 and newer, insignia is replaced with a new command `wix msi inscribe`, but we tell wix to embed the cabinets into the .msi
  (That's what`EmbedCab="yes"` in the Media / MediaTemplate element does) so singning them separately is not necessary. [0]

  [0] https://wixtoolset.org/docs/tools/signing/
2024-11-20 21:03:30 +02:00
JKarasti
e7ae5f3cb2 CI: Use WiX Toolset v5 to build the msi 2024-11-20 21:03:30 +02:00
JKarasti
58ecccfba2 Change: Write Dangerzone.wxs inside the script directly
Also reduce duplication slightly by definig `build_dir`, `cx_freeze_dir` and `dist_dir`
2024-11-20 21:03:29 +02:00
JKarasti
10bc6aa8f1 Fix: Make GUIDs uppercase
See [1]

[1] https://learn.microsoft.com/en-us/windows/win32/msi/guid
2024-11-20 21:03:29 +02:00
JKarasti
7f5793fada Change: Write dangerzone version and upgradecode into Package and SummaryInformation elements directly 2024-11-20 21:03:29 +02:00
JKarasti
90a2843836 Refactor: build_dir_xml() function
- rename for clarity
- remove unnecessary checks
2024-11-20 21:03:29 +02:00
JKarasti
84b8c5106c Change: Wrap all files to be included in the .msi in a ComponentGroupRef
With this, all the files are organised into Components,
each of which points to a Directory defined in the StandardDirectory element.
This simplifies the Feature element considerable as only thing it needs to
include everything in the built msi is a reference to `ApplicationComponents`
2024-11-20 21:03:29 +02:00
JKarasti
ba84c0fb68 Refactor: Simplify build_data() function
- Rename variables to be more clear about what they do:
- reorganise code
- simplify a few checks
2024-11-20 21:03:29 +02:00
JKarasti
4d13333187 Change: Swap Media element with MediaTemplate
This is a new default and makes authoring slightly simpler without any functional changes.
2024-11-20 21:03:29 +02:00
JKarasti
38890259eb Change: Convert Wix UI extension authoring to WiX Toolset v5
Due to limitations of the xml.etree.ElementTree library, add the items in the root element as a dictionary
2024-11-20 21:03:29 +02:00
JKarasti
a2c9e9deed Change: Wrap ProgramFilesFolder component with a StandardDirectory component 2024-11-20 21:03:29 +02:00
JKarasti
3c1e82d4f1 Change: Wrap ProgramMenuFolder component with a StandardDirectory component 2024-11-20 21:03:29 +02:00
jkarasti
17f802915b Change: Disable AllowSameVersionUpgrades
Since running `wix msi validate` with it set to `yes` causes an error.
2024-11-20 21:03:29 +02:00
JKarasti
9104af81c3 Change: Merge Product into Package element
- The Keywords and Description items move under a new SummaryInformation element.
- Shuffle things around so that elements previously under the product element are now under the Package element.
- Rename SummaryCodepage in SummaryInformation to Codepage and remove a duplicate Manufacturer item.
- Remove InstallerVersion and let WiX set it to default value. (500 a.k.a Windows 7)
2024-11-20 21:03:29 +02:00
JKarasti
c62efc7cdd Change: Rename INSTALLDIR to INSTALLFOLDER
It's the new default name for it
2024-11-20 21:03:29 +02:00
JKarasti
435ebf0072 Change: Update WiX schema namespace
Also rename `root_el` to `wix_el`.

WiX version 5 uses the same namespace.
2024-11-20 21:03:29 +02:00
JKarasti
6049a627cb Change: Stop generating an XML declaration at the top of the WiX authoring
It's not needed anymore.
2024-11-20 21:03:29 +02:00
JKarasti
ba20f5a4d0 Fix: Make generated WiX authoring pass WixCop checks
WixCop.exe is a built in formatting tool that comes with WiX toolset v3. This fixes `wix convert` command not beins able to run
2024-11-20 21:03:29 +02:00
JKarasti
b069e0ee10 Fix: SyntaxWarning while generating Dangerzone.wxs 2024-11-20 21:03:29 +02:00
17 changed files with 505 additions and 584 deletions

View file

@ -36,7 +36,7 @@ body:
attributes: attributes:
label: Podman info label: Podman info
description: | description: |
Please copy and paste the following commands in your terminal, and provide us with the output: If the bug occurs during document conversion, or is otherwise related with Podman, please copy and paste the following commands in your terminal, and provide us with the output:
```shell ```shell
podman version podman version

View file

@ -48,7 +48,8 @@ body:
attributes: attributes:
label: Docker info label: Docker info
description: | description: |
Please copy and paste the following commands in your If the bug occurs during document conversion, or is otherwise related
with Docker, please copy and paste the following commands in your
terminal, and provide us with the output: terminal, and provide us with the output:
```shell ```shell

View file

@ -35,7 +35,8 @@ body:
attributes: attributes:
label: Docker info label: Docker info
description: | description: |
Please copy and paste the following commands in your If the bug occurs during document conversion, or is otherwise related
with Docker, please copy and paste the following commands in your
terminal, and provide us with the output: terminal, and provide us with the output:
```shell ```shell

View file

@ -47,6 +47,8 @@ jobs:
version: bookworm version: bookworm
- distro: debian - distro: debian
version: trixie version: trixie
- distro: fedora
version: "39"
- distro: fedora - distro: fedora
version: "40" version: "40"
- distro: fedora - distro: fedora

View file

@ -1,35 +0,0 @@
name: Check branch conformity
on:
pull_request:
jobs:
prevent-fixup-commits:
runs-on: ubuntu-latest
env:
target: debian-bookworm
distro: debian
version: bookworm
steps:
- name: Checkout
uses: actions/checkout@v4
- name: prevent fixup commits
run: |
git fetch origin
git status
git log --pretty=format:%s origin/main..HEAD | grep -ie '^fixup\|^wip' && exit 1 || true
check-changelog:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: ensure CHANGELOG.md is populated
env:
BASE_REF: ${{ github.event.pull_request.base.ref }}
shell: bash
run: |
if git diff --exit-code "origin/${BASE_REF}" -- CHANGELOG.md; then
echo "::warning::No CHANGELOG.md modifications were found in this pull request."
fi

19
.github/workflows/check_push.yml vendored Normal file
View file

@ -0,0 +1,19 @@
name: Check branch conformity
on:
pull_request:
jobs:
prevent-fixup-commits:
runs-on: ubuntu-latest
env:
target: debian-bookworm
distro: debian
version: bookworm
steps:
- name: Checkout
uses: actions/checkout@v4
- name: prevent fixup commits
run: |
git fetch origin
git status
git log --pretty=format:%s origin/main..HEAD | grep -ie '^fixup\|^wip' && exit 1 || true

View file

@ -68,12 +68,6 @@ jobs:
sudo apt-get install -y python3-poetry sudo apt-get install -y python3-poetry
python3 ./install/common/build-image.py python3 ./install/common/build-image.py
- name: Upload container image
uses: actions/upload-artifact@v4
with:
name: container.tar.gz
path: share/container.tar.gz
download-tessdata: download-tessdata:
name: Download and cache Tesseract data name: Download and cache Tesseract data
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -130,13 +124,6 @@ jobs:
- name: Build the MSI installer - name: Build the MSI installer
# NOTE: This also builds the .exe internally. # NOTE: This also builds the .exe internally.
run: poetry run .\install\windows\build-app.bat run: poetry run .\install\windows\build-app.bat
- name: Upload MSI installer
uses: actions/upload-artifact@v4
with:
name: Dangerzone.msi
path: "dist/Dangerzone.msi"
if-no-files-found: error
compression-level: 0
macOS: macOS:
name: "macOS (${{ matrix.arch }})" name: "macOS (${{ matrix.arch }})"
@ -168,15 +155,7 @@ jobs:
- run: poetry install - run: poetry install
- name: Run CLI tests - name: Run CLI tests
run: poetry run make test run: poetry run make test
- name: Build macOS app
run: poetry run python ./install/macos/build-app.py
- name: Upload macOS app
uses: actions/upload-artifact@v4
with:
name: Dangerzone-${{ matrix.arch }}.app
path: "dist/Dangerzone.app"
if-no-files-found: error
compression-level: 0
build-deb: build-deb:
needs: needs:
- build-container-image - build-container-image
@ -241,7 +220,7 @@ jobs:
if: matrix.distro == 'debian' && matrix.version == 'bookworm' if: matrix.distro == 'debian' && matrix.version == 'bookworm'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: dangerzone.deb name: dangerzone-${{ matrix.distro }}-${{ matrix.version }}.deb
path: "deb_dist/dangerzone_*_*.deb" path: "deb_dist/dangerzone_*_*.deb"
if-no-files-found: error if-no-files-found: error
compression-level: 0 compression-level: 0
@ -280,7 +259,7 @@ jobs:
- name: Download Dangerzone .deb - name: Download Dangerzone .deb
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: dangerzone.deb name: dangerzone-debian-bookworm.deb
path: "deb_dist/" path: "deb_dist/"
- name: Build end-user environment - name: Build end-user environment
@ -309,7 +288,7 @@ jobs:
strategy: strategy:
matrix: matrix:
distro: ["fedora"] distro: ["fedora"]
version: ["40", "41"] version: ["39", "40", "41"]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -343,14 +322,6 @@ jobs:
./dev_scripts/env.py --distro ${{ matrix.distro }} --version ${{ matrix.version }} \ ./dev_scripts/env.py --distro ${{ matrix.distro }} --version ${{ matrix.version }} \
run --dev --no-gui ./dangerzone/install/linux/build-rpm.py run --dev --no-gui ./dangerzone/install/linux/build-rpm.py
- name: Upload Dangerzone .rpm
uses: actions/upload-artifact@v4
with:
name: dangerzone-${{ matrix.distro }}-${{ matrix.version }}.rpm
path: "dist/dangerzone-*.x86_64.rpm"
if-no-files-found: error
compression-level: 0
# Reclaim some space in this step, now that the dev environment is no # Reclaim some space in this step, now that the dev environment is no
# longer necessary. Previously, we encountered out-of-space issues while # longer necessary. Previously, we encountered out-of-space issues while
# running this CI job. # running this CI job.
@ -361,7 +332,7 @@ jobs:
run: | run: |
./dev_scripts/env.py --distro ${{ matrix.distro }} \ ./dev_scripts/env.py --distro ${{ matrix.distro }} \
--version ${{ matrix.version }} \ --version ${{ matrix.version }} \
build build --download-pyside6
- name: Run a test command - name: Run a test command
run: | run: |
@ -396,6 +367,8 @@ jobs:
version: bookworm version: bookworm
- distro: debian - distro: debian
version: trixie version: trixie
- distro: fedora
version: "39"
- distro: fedora - distro: fedora
version: "40" version: "40"
- distro: fedora - distro: fedora

View file

@ -11,16 +11,15 @@ jobs:
include: include:
- runs-on: ubuntu-latest - runs-on: ubuntu-latest
arch: i686 arch: i686
# Do not scan Silicon mac for now to avoid masking release scan results for other plaforms. - runs-on: macos-latest
# - runs-on: macos-latest arch: arm64
# arch: arm64
runs-on: ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Download container image for the latest release and load it - name: Download container image for the latest release and load it
run: | run: |
VERSION=$(curl https://api.github.com/repos/freedomofpress/dangerzone/releases/latest | grep "tag_name" | cut -d '"' -f 4) VERSION=$(curl https://api.github.com/repos/freedomofpress/dangerzone/releases/latest | jq -r '.tag_name')
CONTAINER_FILENAME=container-${VERSION:1}-${{ matrix.arch }}.tar.gz CONTAINER_FILENAME=container-${VERSION:1}-${{ matrix.arch }}.tar.gz
wget https://github.com/freedomofpress/dangerzone/releases/download/${VERSION}/${CONTAINER_FILENAME} -O ${CONTAINER_FILENAME} wget https://github.com/freedomofpress/dangerzone/releases/download/${VERSION}/${CONTAINER_FILENAME} -O ${CONTAINER_FILENAME}
docker load -i ${CONTAINER_FILENAME} docker load -i ${CONTAINER_FILENAME}

View file

@ -260,17 +260,11 @@ The following instructions require typing commands in a terminal in dom0.
``` ```
qvm-create --class AppVM --label red --template fedora-40-dz dz qvm-create --class AppVM --label red --template fedora-40-dz dz
qvm-volume resize dz:private $(numfmt --from=auto 20Gi)
``` ```
> :bulb: Alternatively, you can use a different app qube for Dangerzone > :bulb: Alternatively, you can use a different app qube for Dangerzone
> development. In that case, replace `dz` with the qube of your choice in the > development. In that case, replace `dz` with the qube of your choice in the
> steps below. > steps below.
>
> In the commands above, we also resize the private volume of the `dz` qube
> to 20GiB, since you may need some extra storage space when developing on
> Dangerzone (e.g., for container images, Tesseract data, and Python
> virtualenvs).
4. Add an RPC policy (`/etc/qubes/policy.d/50-dangerzone.policy`) that will 4. Add an RPC policy (`/etc/qubes/policy.d/50-dangerzone.policy`) that will
allow launching a disposable qube (`dz-dvm`) when Dangerzone converts a allow launching a disposable qube (`dz-dvm`) when Dangerzone converts a
@ -314,9 +308,18 @@ test it.
1. Install the `.rpm` package you just copied 1. Install the `.rpm` package you just copied
```sh ```sh
sudo dnf install 'dnf-command(config-manager)'
sudo dnf-3 config-manager --add-repo=https://packages.freedom.press/yum-tools-prod/dangerzone/dangerzone.repo
sudo dnf install ~/QubesIncoming/dz/*.rpm sudo dnf install ~/QubesIncoming/dz/*.rpm
``` ```
In the above steps, we add the Dangerzone repo because it includes the
necessary PySide6 RPM in order to make Dangerzone work.
> [!NOTE]
> During the installation, you will be asked to
> [verify the Dangerzone GPG key](INSTALL.md#verifying-dangerzone-gpg-key).
2. Shutdown the `fedora-40-dz` template 2. Shutdown the `fedora-40-dz` template
### Developing Dangerzone ### Developing Dangerzone

View file

@ -12,15 +12,6 @@ since 0.4.1, and this project adheres to [Semantic Versioning](https://semver.or
- Disable gVisor's DirectFS feature ([#226](https://github.com/freedomofpress/dangerzone/issues/226)). - Disable gVisor's DirectFS feature ([#226](https://github.com/freedomofpress/dangerzone/issues/226)).
Thanks [EtiennePerot](https://github.com/EtiennePerot) for the contribution. Thanks [EtiennePerot](https://github.com/EtiennePerot) for the contribution.
### Removed
- Platform support: Drop support for Fedora 39, since it's end-of-life ([#999](https://github.com/freedomofpress/dangerzone/pull/999))
### Development changes
- Build Dangerzone MSI with Wix Toolset 5 ([#929](https://github.com/freedomofpress/dangerzone/pull/929)).
Thanks [@jkarasti](https://github.com/jkarasti) for the contribution.
## [0.8.0](https://github.com/freedomofpress/dangerzone/compare/v0.8.0...0.7.1) ## [0.8.0](https://github.com/freedomofpress/dangerzone/compare/v0.8.0...0.7.1)
### Added ### Added

View file

@ -1,21 +1,8 @@
## MacOS ## MacOS
See instructions in [README.md](README.md#macos).
- Download [Dangerzone 0.8.0 for Mac (Apple Silicon CPU)](https://github.com/freedomofpress/dangerzone/releases/download/v0.8.0/Dangerzone-0.8.0-arm64.dmg)
- Download [Dangerzone 0.8.0 for Mac (Intel CPU)](https://github.com/freedomofpress/dangerzone/releases/download/v0.8.0/Dangerzone-0.8.0-i686.dmg)
You can also install Dangerzone for Mac using [Homebrew](https://brew.sh/): `brew install --cask dangerzone`
> **Note**: you will also need to install [Docker Desktop](https://www.docker.com/products/docker-desktop/).
> This program needs to run alongside Dangerzone at all times, since it is what allows Dangerzone to
> create the secure environment.
## Windows ## Windows
See instructions in [README.md](README.md#windows).
- Download [Dangerzone 0.8.0 for Windows](https://github.com/freedomofpress/dangerzone/releases/download/v0.8.0/Dangerzone-0.8.0.msi)
> **Note**: you will also need to install [Docker Desktop](https://www.docker.com/products/docker-desktop/).
> This program needs to run alongside Dangerzone at all times, since it is what allows Dangerzone to
> create the secure environment.
## Linux ## Linux
On Linux, Dangerzone uses [Podman](https://podman.io/) instead of Docker Desktop for creating On Linux, Dangerzone uses [Podman](https://podman.io/) instead of Docker Desktop for creating
@ -31,6 +18,7 @@ Dangerzone is available for:
- Debian 11 (bullseye) - Debian 11 (bullseye)
- Fedora 41 - Fedora 41
- Fedora 40 - Fedora 40
- Fedora 39
- Tails - Tails
- Qubes OS (beta support) - Qubes OS (beta support)
@ -137,6 +125,23 @@ sudo apt install -y dangerzone
### Fedora ### Fedora
<table>
<tr>
<td>
<details>
<summary><i>:information_source: Backport notice for Fedora users regarding the <code>python3-pyside6</code> package</i></summary>
</br>
Fedora 39+ onwards does not provide official Python bindings for Qt. For
this reason, we provide our own `python3-pyside6` package (see
[build instructions](https://github.com/freedomofpress/maint-dangerzone-pyside6))
from our YUM repo. For a deeper dive on this subject, you may read
[this issue](https://github.com/freedomofpress/dangerzone/issues/211#issuecomment-1827777122).
</details>
</td>
</tr>
</table>
Type the following commands in a terminal: Type the following commands in a terminal:
``` ```

197
QA.md
View file

@ -1,197 +0,0 @@
## QA
To ensure that new releases do not introduce regressions, and support existing
and newer platforms, we have to test that the produced packages work as expected.
Check the following:
- [ ] Make sure that the tip of the `main` branch passes the CI tests.
- [ ] Make sure that the Apple account has a valid application password and has
agreed to the latest Apple terms (see [macOS release](#macos-release)
section).
Because it is repetitive, we wrote a script to help with the QA.
It can run the tasks for you, pausing when it needs manual intervention.
You can run it with a command like:
```bash
poetry run ./dev_scripts/qa.py {distro}-{version}
```
### The checklist
- [ ] Create a test build in Windows and make sure it works:
- [ ] Check if the suggested Python version is still supported.
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests.
- [ ] Build and run the Dangerzone .exe
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in macOS (Intel CPU) and make sure it works:
- [ ] Check if the suggested Python version is still supported.
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests.
- [ ] Create and run an app bundle.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in macOS (M1/2 CPU) and make sure it works:
- [ ] Check if the suggested Python version is still supported.
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests.
- [ ] Create and run an app bundle.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in the most recent Ubuntu LTS platform (Ubuntu 24.04
as of writing this) and make sure it works:
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests.
- [ ] Create a .deb package and install it system-wide.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in the most recent Fedora platform (Fedora 41 as of
writing this) and make sure it works:
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests.
- [ ] Create an .rpm package and install it system-wide.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in the most recent Qubes Fedora template (Fedora 40 as
of writing this) and make sure it works:
- [ ] Create a new development environment with Poetry.
- [ ] Run the Dangerzone tests.
- [ ] Create a Qubes .rpm package and install it system-wide.
- [ ] Ensure that the Dangerzone application appears in the "Applications"
tab.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below) and make sure
they spawn disposable qubes.
### Scenarios
#### 1. Dangerzone correctly identifies that Docker/Podman is not installed
_(Only for MacOS / Windows)_
Temporarily hide the Docker/Podman binaries, e.g., rename the `docker` /
`podman` binaries to something else. Then run Dangerzone. Dangerzone should
prompt the user to install Docker/Podman.
#### 2. Dangerzone correctly identifies that Docker is not running
_(Only for MacOS / Windows)_
Stop the Docker Desktop application. Then run Dangerzone. Dangerzone should
prompt the user to start Docker Desktop.
#### 3. Updating Dangerzone handles external state correctly.
_(Applies to Windows/MacOS)_
Install the previous version of Dangerzone, downloaded from the website.
Open the Dangerzone application and enable some non-default settings.
**If there are new settings, make sure to change those as well**.
Close the Dangerzone application and get the container image for that
version. For example:
```
$ docker images dangerzone.rocks/dangerzone:latest
REPOSITORY TAG IMAGE ID CREATED SIZE
dangerzone.rocks/dangerzone latest <image ID> <date> <size>
```
Then run the version under QA and ensure that the settings remain changed.
Afterwards check that new docker image was installed by running the same command
and seeing the following differences:
```
$ docker images dangerzone.rocks/dangerzone:latest
REPOSITORY TAG IMAGE ID CREATED SIZE
dangerzone.rocks/dangerzone latest <different ID> <newer date> <different size>
```
#### 4. Dangerzone successfully installs the container image
_(Only for Linux)_
Remove the Dangerzone container image from Docker/Podman. Then run Dangerzone.
Dangerzone should install the container image successfully.
#### 5. Dangerzone retains the settings of previous runs
Run Dangerzone and make some changes in the settings (e.g., change the OCR
language, toggle whether to open the document after conversion, etc.). Restart
Dangerzone. Dangerzone should show the settings that the user chose.
#### 6. Dangerzone reports failed conversions
Run Dangerzone and convert the `tests/test_docs/sample_bad_pdf.pdf` document.
Dangerzone should fail gracefully, by reporting that the operation failed, and
showing the following error message:
> The document format is not supported
#### 7. Dangerzone succeeds in converting multiple documents
Run Dangerzone against a list of documents, and tick all options. Ensure that:
* Conversions take place sequentially.
* Attempting to close the window while converting asks the user if they want to
abort the conversions.
* Conversions are completed successfully.
* Conversions show individual progress in real-time (double-check for Qubes).
* _(Only for Linux)_ The resulting files open with the PDF viewer of our choice.
* OCR seems to have detected characters in the PDF files.
* The resulting files have been saved with the proper suffix, in the proper
location.
* The original files have been saved in the `unsafe/` directory.
#### 8. Dangerzone is able to handle drag-n-drop
Run Dangerzone against a set of documents that you drag-n-drop. Files should be
added and conversion should run without issue.
> [!TIP]
> On our end-user container environments for Linux, we can start a file manager
> with `thunar &`.
#### 9. Dangerzone CLI succeeds in converting multiple documents
_(Only for Windows and Linux)_
Run Dangerzone CLI against a list of documents. Ensure that conversions happen
sequentially, are completed successfully, and we see their progress.
#### 10. Dangerzone can open a document for conversion via right-click -> "Open With"
_(Only for Windows, MacOS and Qubes)_
Go to a directory with office documents, right-click on one, and click on "Open
With". We should be able to open the file with Dangerzone, and then convert it.
#### 11. Dangerzone shows helpful errors for setup issues on Qubes
_(Only for Qubes)_
Check what errors does Dangerzone throw in the following scenarios. The errors
should point the user to the Qubes notifications in the top-right corner:
1. The `dz-dvm` template does not exist. We can trigger this scenario by
temporarily renaming this template.
2. The Dangerzone RPC policy does not exist. We can trigger this scenario by
temporarily renaming the `dz.Convert` policy.
3. The `dz-dvm` disposable Qube cannot start due to insufficient resources. We
can trigger this scenario by temporarily increasing the minimum required RAM
of the `dz-dvm` template to more than the available amount.

View file

@ -6,21 +6,33 @@ Take potentially dangerous PDFs, office documents, or images and convert them to
| ![Settings](./assets/screenshot1.png) | ![Converting](./assets/screenshot2.png) | ![Settings](./assets/screenshot1.png) | ![Converting](./assets/screenshot2.png)
|--|--| |--|--|
Dangerzone works like this: You give it a document that you don't know if you can trust (for example, an email attachment). Inside of a sandbox, Dangerzone converts the document to a PDF (if it isn't already one), and then converts the PDF into raw pixel data: a huge list of RGB color values for each page. Then, outside of the sandbox, Dangerzone takes this pixel data and converts it back into a PDF. Dangerzone works like this: You give it a document that you don't know if you can trust (for example, an email attachment). Inside of a sandbox, Dangerzone converts the document to a PDF (if it isn't already one), and then converts the PDF into raw pixel data: a huge list of RGB color values for each page. Then, in a separate sandbox, Dangerzone takes this pixel data and converts it back into a PDF.
_Read more about Dangerzone in the [official site](https://dangerzone.rocks/about/)._ _Read more about Dangerzone in the [official site](https://dangerzone.rocks/about/)._
## Getting started ## Getting started
Follow the instructions for each platform: ### MacOS
- Download [Dangerzone 0.8.0 for Mac (Apple Silicon CPU)](https://github.com/freedomofpress/dangerzone/releases/download/v0.8.0/Dangerzone-0.8.0-arm64.dmg)
- Download [Dangerzone 0.8.0 for Mac (Intel CPU)](https://github.com/freedomofpress/dangerzone/releases/download/v0.8.0/Dangerzone-0.8.0-i686.dmg)
* [macOS](https://github.com/freedomofpress/dangerzone/blob/v0.8.0//INSTALL.md#macos) You can also install Dangerzone for Mac using [Homebrew](https://brew.sh/): `brew install --cask dangerzone`
* [Windows](https://github.com/freedomofpress/dangerzone/blob/v0.8.0//INSTALL.md#windows)
* [Ubuntu Linux](https://github.com/freedomofpress/dangerzone/blob/v0.8.0/INSTALL.md#ubuntu-debian) > **Note**: you will also need to install [Docker Desktop](https://www.docker.com/products/docker-desktop/).
* [Debian Linux](https://github.com/freedomofpress/dangerzone/blob/v0.8.0/INSTALL.md#ubuntu-debian) > This program needs to run alongside Dangerzone at all times, since it is what allows Dangerzone to
* [Fedora Linux](https://github.com/freedomofpress/dangerzone/blob/v0.8.0/INSTALL.md#fedora) > create the secure environment.
* [Qubes OS (beta)](https://github.com/freedomofpress/dangerzone/blob/v0.8.0/INSTALL.md#qubes-os)
* [Tails](https://github.com/freedomofpress/dangerzone/blob/v0.8.0/INSTALL.md#tails) ### Windows
- Download [Dangerzone 0.8.0 for Windows](https://github.com/freedomofpress/dangerzone/releases/download/v0.8.0/Dangerzone-0.8.0.msi)
> **Note**: you will also need to install [Docker Desktop](https://www.docker.com/products/docker-desktop/).
> This program needs to run alongside Dangerzone at all times, since it is what allows Dangerzone to
> create the secure environment.
### Linux
See [installing Dangerzone](INSTALL.md#linux) for adding the Linux repositories to your system.
## Some features ## Some features

View file

@ -1,23 +1,21 @@
# Release instructions # Release instructions
This section documents how we currently release Dangerzone for the different distributions we support. This section documents the release process. Unless you're a dangerzone developer making a release, you'll probably never need to follow it.
## Pre-release ## Pre-release
Here is a list of tasks that should be done before issuing the release: Before making a release, all of these should be complete:
- [ ] Create a new issue named **QA and Release for version \<VERSION\>**, to track the general progress. - [ ] Copy the checkboxes from these instructions onto a new issue and call it **QA and Release version \<VERSION\>**
You can generate its content with the the `poetry run ./dev_scripts/generate-release-tasks.py` command.
- [ ] [Add new Linux platforms and remove obsolete ones](https://github.com/freedomofpress/dangerzone/blob/main/RELEASE.md#add-new-platforms-and-remove-obsolete-ones) - [ ] [Add new Linux platforms and remove obsolete ones](https://github.com/freedomofpress/dangerzone/blob/main/RELEASE.md#add-new-platforms-and-remove-obsolete-ones)
- [ ] Bump the Python dependencies using `poetry lock` - [ ] Bump the Python dependencies using `poetry lock`
- [ ] [Check for official PySide6 versions](https://github.com/freedomofpress/dangerzone/blob/main/RELEASE.md#check-for-official-pyside6-versions)
- [ ] Update `version` in `pyproject.toml` - [ ] Update `version` in `pyproject.toml`
- [ ] Update `share/version.txt` - [ ] Update `share/version.txt`
- [ ] Update the "Version" field in `install/linux/dangerzone.spec` - [ ] Update the "Version" field in `install/linux/dangerzone.spec`
- [ ] Bump the Debian version by adding a new changelog entry in `debian/changelog` - [ ] Bump the Debian version by adding a new changelog entry in `debian/changelog`
- [ ] Update screenshot in `README.md`, if necessary - [ ] Update screenshot in `README.md`, if necessary
- [ ] CHANGELOG.md should be updated to include a list of all major changes since the last release - [ ] CHANGELOG.md should be updated to include a list of all major changes since the last release
- [ ] A draft release should be created. Copy the release notes text from the template at [`docs/templates/release-notes`](https://github.com/freedomofpress/dangerzone/tree/main/docs/templates/)
- [ ] Do the QA tasks
## Add new Linux platforms and remove obsolete ones ## Add new Linux platforms and remove obsolete ones
@ -40,12 +38,22 @@ In case of a new version (beta, RC, or official release):
`BUILD.md` files where necessary. `BUILD.md` files where necessary.
4. Send a PR with the above changes. 4. Send a PR with the above changes.
In case of the removal of a version: In case of an EOL version:
1. Remove any mention to this version from our repo. 1. Remove any mention to this version from our repo.
* Consult the previous paragraph, but also `grep` your way around. * Consult the previous paragraph, but also `grep` your way around.
2. Add a notice in our `CHANGELOG.md` about the version removal. 2. Add a notice in our `CHANGELOG.md` about the version removal.
## Check for official PySide6 versions
PySide6 6.7.0 is available from the Fedora Rawhide repo, and we expect that a
similar version will be pushed soon to the rest of the stable releases. Prior to
a release, we should check if this has happened already. Once this happens, we
should update our CI tests accordingly, and remove this notice.
For more info, read:
https://github.com/freedomofpress/maint-dangerzone-pyside6/issues/5
## Large Document Testing ## Large Document Testing
Parallel to the QA process, the release candidate should be put through the large document tests in a dedicated machine to run overnight. Parallel to the QA process, the release candidate should be put through the large document tests in a dedicated machine to run overnight.
@ -54,13 +62,192 @@ Follow the instructions in `docs/developer/TESTING.md` to run the tests.
These tests will identify any regressions or progression in terms of document coverage. These tests will identify any regressions or progression in terms of document coverage.
## QA
To ensure that new releases do not introduce regressions, and support existing
and newer platforms, we have to do the following:
- [ ] Make sure that the tip of the `main` branch passes the CI tests.
- [ ] Make sure that the Apple account has a valid application password and has
agreed to the latest Apple terms (see [macOS release](#macos-release)
section).
- [ ] Create a test build in Windows and make sure it works:
- [ ] Check if the suggested Python version is still supported.
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Run the Dangerzone tests.
- [ ] Build and run the Dangerzone .exe
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in macOS (Intel CPU) and make sure it works:
- [ ] Check if the suggested Python version is still supported.
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Run the Dangerzone tests.
- [ ] Create and run an app bundle.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in macOS (M1/2 CPU) and make sure it works:
- [ ] Check if the suggested Python version is still supported.
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Run the Dangerzone tests.
- [ ] Create and run an app bundle.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in the most recent Ubuntu LTS platform (Ubuntu 24.04
as of writing this) and make sure it works:
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Run the Dangerzone tests.
- [ ] Create a .deb package and install it system-wide.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in the most recent Fedora platform (Fedora 41 as of
writing this) and make sure it works:
- [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses
the new image.
- [ ] Run the Dangerzone tests.
- [ ] Create an .rpm package and install it system-wide.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
- [ ] Create a test build in the most recent Qubes Fedora template (Fedora 40 as
of writing this) and make sure it works:
- [ ] Create a new development environment with Poetry.
- [ ] Run the Dangerzone tests.
- [ ] Create a Qubes .rpm package and install it system-wide.
- [ ] Ensure that the Dangerzone application appears in the "Applications"
tab.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below) and make sure
they spawn disposable qubes.
### Scenarios
#### 1. Dangerzone correctly identifies that Docker/Podman is not installed
_(Only for MacOS / Windows)_
Temporarily hide the Docker/Podman binaries, e.g., rename the `docker` /
`podman` binaries to something else. Then run Dangerzone. Dangerzone should
prompt the user to install Docker/Podman.
#### 2. Dangerzone correctly identifies that Docker is not running
_(Only for MacOS / Windows)_
Stop the Docker Desktop application. Then run Dangerzone. Dangerzone should
prompt the user to start Docker Desktop.
#### 3. Updating Dangerzone handles external state correctly.
_(Applies to Windows/MacOS)_
Install the previous version of Dangerzone, downloaded from the website.
Open the Dangerzone application and enable some non-default settings.
**If there are new settings, make sure to change those as well**.
Close the Dangerzone application and get the container image for that
version. For example:
```
$ docker images dangerzone.rocks/dangerzone:latest
REPOSITORY TAG IMAGE ID CREATED SIZE
dangerzone.rocks/dangerzone latest <image ID> <date> <size>
```
Then run the version under QA and ensure that the settings remain changed.
Afterwards check that new docker image was installed by running the same command
and seeing the following differences:
```
$ docker images dangerzone.rocks/dangerzone:latest
REPOSITORY TAG IMAGE ID CREATED SIZE
dangerzone.rocks/dangerzone latest <different ID> <newer date> <different size>
```
#### 4. Dangerzone successfully installs the container image
_(Only for Linux)_
Remove the Dangerzone container image from Docker/Podman. Then run Dangerzone.
Dangerzone should install the container image successfully.
#### 5. Dangerzone retains the settings of previous runs
Run Dangerzone and make some changes in the settings (e.g., change the OCR
language, toggle whether to open the document after conversion, etc.). Restart
Dangerzone. Dangerzone should show the settings that the user chose.
#### 6. Dangerzone reports failed conversions
Run Dangerzone and convert the `tests/test_docs/sample_bad_pdf.pdf` document.
Dangerzone should fail gracefully, by reporting that the operation failed, and
showing the following error message:
> The document format is not supported
#### 7. Dangerzone succeeds in converting multiple documents
Run Dangerzone against a list of documents, and tick all options. Ensure that:
* Conversions take place sequentially.
* Attempting to close the window while converting asks the user if they want to
abort the conversions.
* Conversions are completed successfully.
* Conversions show individual progress in real-time (double-check for Qubes).
* _(Only for Linux)_ The resulting files open with the PDF viewer of our choice.
* OCR seems to have detected characters in the PDF files.
* The resulting files have been saved with the proper suffix, in the proper
location.
* The original files have been saved in the `unsafe/` directory.
#### 8. Dangerzone is able to handle drag-n-drop
Run Dangerzone against a set of documents that you drag-n-drop. Files should be
added and conversion should run without issue.
> [!TIP]
> On our end-user container environments for Linux, we can start a file manager
> with `thunar &`.
#### 9. Dangerzone CLI succeeds in converting multiple documents
_(Only for Windows and Linux)_
Run Dangerzone CLI against a list of documents. Ensure that conversions happen
sequentially, are completed successfully, and we see their progress.
#### 10. Dangerzone can open a document for conversion via right-click -> "Open With"
_(Only for Windows, MacOS and Qubes)_
Go to a directory with office documents, right-click on one, and click on "Open
With". We should be able to open the file with Dangerzone, and then convert it.
#### 11. Dangerzone shows helpful errors for setup issues on Qubes
_(Only for Qubes)_
Check what errors does Dangerzone throw in the following scenarios. The errors
should point the user to the Qubes notifications in the top-right corner:
1. The `dz-dvm` template does not exist. We can trigger this scenario by
temporarily renaming this template.
2. The Dangerzone RPC policy does not exist. We can trigger this scenario by
temporarily renaming the `dz.Convert` policy.
3. The `dz-dvm` disposable Qube cannot start due to insufficient resources. We
can trigger this scenario by temporarily increasing the minimum required RAM
of the `dz-dvm` template to more than the available amount.
## Release ## Release
Once we are confident that the release will be out shortly, and doesn't need any more changes: Once we are confident that the release will be out shortly, and doesn't need any more changes:
- [ ] Create a PGP-signed git tag for the version, e.g., for dangerzone `v0.1.0`: - [ ] Create a PGP-signed git tag for the version, e.g., for dangerzone `v0.1.0`:
```bash ```
git tag -s v0.1.0 git tag -s v0.1.0
git push origin v0.1.0 git push origin v0.1.0
``` ```
@ -76,8 +263,6 @@ Once we are confident that the release will be out shortly, and doesn't need any
### macOS Release ### macOS Release
This needs to happen for both Silicon and Intel chipsets.
#### Initial Setup #### Initial Setup
- Build machine must have: - Build machine must have:
@ -92,85 +277,48 @@ This needs to happen for both Silicon and Intel chipsets.
#### Releasing and Signing #### Releasing and Signing
Here is what you need to do:
- [ ] Verify and install the latest supported Python version from - [ ] Verify and install the latest supported Python version from
[python.org](https://www.python.org/downloads/macos/) (do not use the one from [python.org](https://www.python.org/downloads/macos/) (do not use the one from
brew as it is known to [cause issues](https://github.com/freedomofpress/dangerzone/issues/471)) brew as it is known to [cause issues](https://github.com/freedomofpress/dangerzone/issues/471))
* In case of a new Python installation or minor version upgrade, e.g., from
- [ ] Checkout the dependencies, and clean your local copy: 3.11 to 3.12 , reinstall Poetry with `python3 -m pip install poetry`
* You can verify the correct Python version is used with `poetry debug info`
```bash - [ ] Verify and checkout the git tag for this release
- [ ] Run `poetry install --sync`
# In case of a new Python installation or minor version upgrade, e.g., from - [ ] On the silicon mac, build the container image:
# 3.11 to 3.12, reinstall Poetry
python3 -m pip install poetry
# You can verify the correct Python version is used
poetry debug info
# Replace with the actual version
export DZ_VERSION=$(cat share/version.txt)
# Verify and checkout the git tag for this release:
git checkout -f v$VERSION
# Clean the git repository
git clean -df
# Clean up the environment
poetry env remove --all
# Install the dependencies
poetry install --sync
``` ```
python3 ./install/common/build-image.py
- [ ] Build the container image and the OCR language data
```bash
poetry run ./install/common/build-image.py
poetry run ./install/common/download-tessdata.py
# Copy the container image to the assets folder
cp share/container.tar.gz ~dz/release-assets/$VERSION/dangerzone-$VERSION-arm64.tar.gz
cp share/image-id.txt ~dz/release-assets/$VERSION/.
``` ```
Then copy the `share/container.tar.gz` to the assets folder on `dangerzone-$VERSION-arm64.tar.gz`, along with the `share/image-id.txt` file.
- [ ] Build the app bundle - [ ] Run `poetry run ./install/macos/build-app.py`; this will make `dist/Dangerzone.app`
```bash
poetry run ./install/macos/build-app.py
```
- [ ] Make sure that the build application works with the containerd graph - [ ] Make sure that the build application works with the containerd graph
driver (see [#933](https://github.com/freedomofpress/dangerzone/issues/933)) driver (see [#933](https://github.com/freedomofpress/dangerzone/issues/933))
- [ ] Sign the application bundle, and notarize it - [ ] Run `poetry run ./install/macos/build-app.py --only-codesign`; this will make `dist/Dangerzone.dmg`
* You need to run this command as the account that has access to the code signing certificate
You need to run this command as the account that has access to the code signing certificate * You must run this command from the MacOS UI, from a terminal application.
- [ ] Notarize it: `xcrun notarytool submit --wait --apple-id "<email>" --keychain-profile "dz-notarytool-release-key" dist/Dangerzone.dmg`
This command assumes that you have created, and stored in the Keychain, an * You need to change the `<email>` in the above command with the email
application password associated with your Apple Developer ID, which will be associated with the Apple Developer ID.
used specifically for `notarytool`. * This command assumes that you have created, and stored in the Keychain, an
application password associated with your Apple Developer ID, which will be
used specifically for `notarytool`.
- [ ] Wait for it to get approved:
* If it gets rejected, you should be able to see why with the same command
(or use the `log` option for a more verbose JSON output)
* You will also receive an update in your email.
- [ ] After it's approved, staple the ticket: `xcrun stapler staple dist/Dangerzone.dmg`
```bash This process ends up with the final file:
# Sign the .App and make it a .dmg
poetry run ./install/macos/build-app.py --only-codesign
# Notarize it. You must run this command from the MacOS UI ```
# from a terminal application. dist/Dangerzone.dmg
xcrun notarytool submit ./dist/Dangerzone.dmg --apple-id $APPLE_ID --keychain-profile "dz-notarytool-release-key" --wait && xcrun stapler staple dist/Dangerzone.dmg ```
# Copy the .dmg to the assets folder Rename `Dangerzone.dmg` to `Dangerzone-$VERSION.dmg`.
ARCH=$(uname -m)
if [ "$ARCH" = "x86_64" ]; then
ARCH="i686"
fi
cp dist/Dangerzone.dmg ~dz/release-assets/$VERSION/Dangerzone-$VERSION-$ARCH.dmg
```
### Windows Release ### Windows Release
The Windows release is performed in a Windows 11 virtual machine (as opposed to a physical one). The Windows release is performed in a Windows 11 virtual machine as opposed to a physical one.
#### Initial Setup #### Initial Setup
@ -184,31 +332,8 @@ The Windows release is performed in a Windows 11 virtual machine (as opposed to
#### Releasing and Signing #### Releasing and Signing
- [ ] Checkout the dependencies, and clean your local copy: - [ ] Verify and checkout the git tag for this release
```bash - [ ] Run `poetry install --sync`
# In case of a new Python installation or minor version upgrade, e.g., from
# 3.11 to 3.12, reinstall Poetry
python3 -m pip install poetry
# You can verify the correct Python version is used
poetry debug info
# Replace with the actual version
export DZ_VERSION=$(cat share/version.txt)
# Verify and checkout the git tag for this release:
git checkout -f v$VERSION
# Clean the git repository
git clean -df
# Clean up the environment
poetry env remove --all
# Install the dependencies
poetry install --sync
```
- [ ] Copy the container image into the VM - [ ] Copy the container image into the VM
> [!IMPORTANT] > [!IMPORTANT]
> Instead of running `python .\install\windows\build-image.py` in the VM, run the build image script on the host (making sure to build for `linux/amd64`). Copy `share/container.tar.gz` and `share/image-id.txt` from the host into the `share` folder in the VM. > Instead of running `python .\install\windows\build-image.py` in the VM, run the build image script on the host (making sure to build for `linux/amd64`). Copy `share/container.tar.gz` and `share/image-id.txt` from the host into the `share` folder in the VM.
@ -240,15 +365,21 @@ instructions in our build section](https://github.com/freedomofpress/dangerzone/
or create your own locally with: or create your own locally with:
```sh ```sh
# Create and run debian bookworm development environment
./dev_scripts/env.py --distro debian --version bookworm build-dev ./dev_scripts/env.py --distro debian --version bookworm build-dev
./dev_scripts/env.py --distro debian --version bookworm run --dev bash ./dev_scripts/env.py --distro debian --version bookworm run --dev bash
cd dangerzone
```
# Build the latest container Build the latest container:
./dev_scripts/env.py --distro debian --version bookworm run --dev bash -c "cd dangerzone && poetry run ./install/common/build-image.py"
# Create a .deb ```sh
./dev_scripts/env.py --distro debian --version bookworm run --dev bash -c "cd dangerzone && ./install/linux/build-deb.py" python3 ./install/common/build-image.py
```
Create a .deb:
```sh
./install/linux/build-deb.py
``` ```
Publish the .deb under `./deb_dist` to the Publish the .deb under `./deb_dist` to the
@ -267,12 +398,22 @@ or create your own locally with:
```sh ```sh
./dev_scripts/env.py --distro fedora --version 41 build-dev ./dev_scripts/env.py --distro fedora --version 41 build-dev
./dev_scripts/env.py --distro fedora --version 41 run --dev bash
cd dangerzone
```
# Build the latest container (skip if already built): Build the latest container:
./dev_scripts/env.py --distro fedora --version 41 run --dev bash -c "cd dangerzone && poetry run ./install/common/build-image.py"
# Create a .rpm: ```sh
./dev_scripts/env.py --distro fedora --version 41 run --dev bash -c "cd dangerzone && ./install/linux/build-rpm.py" python3 ./install/common/build-image.py
```
Copy the container image to the assets folder on `dangerzone-$VERSION-i686.tar.gz`.
Create a .rpm:
```sh
./install/linux/build-rpm.py
``` ```
Publish the .rpm under `./dist` to the Publish the .rpm under `./dist` to the
@ -283,7 +424,7 @@ Publish the .rpm under `./dist` to the
Create a .rpm for Qubes: Create a .rpm for Qubes:
```sh ```sh
./dev_scripts/env.py --distro fedora --version 41 run --dev bash -c "cd dangerzone && ./install/linux/build-rpm.py --qubes" ./install/linux/build-rpm.py --qubes
``` ```
and similarly publish it to the [`freedomofpress/yum-tools-prod`](https://github.com/freedomofpress/yum-tools-prod) and similarly publish it to the [`freedomofpress/yum-tools-prod`](https://github.com/freedomofpress/yum-tools-prod)
@ -291,37 +432,36 @@ repo.
## Publishing the Release ## Publishing the Release
To publish the release, you can follow these steps: To publish the release:
- [ ] Create an archive of the Dangerzone source in `tar.gz` format: - [ ] Create an archive of the Dangerzone source in `tar.gz` format:
```bash * You can use the following command:
export VERSION=$(cat share/version.txt)
git archive --format=tar.gz -o dangerzone-${VERSION:?}.tar.gz --prefix=dangerzone/ v${VERSION:?} ```
``` export DZ_VERSION=$(cat share/version.txt)
git archive --format=tar.gz -o dangerzone-${DZ_VERSION:?}.tar.gz --prefix=dangerzone/ v${DZ_VERSION:?}
```
- [ ] Run container scan on the produced container images (some time may have passed since the artifacts were built) - [ ] Run container scan on the produced container images (some time may have passed since the artifacts were built)
```bash ```
gunzip --keep -c ./share/container.tar.gz > /tmp/container.tar gunzip --keep -c ./share/container.tar.gz > /tmp/container.tar
docker pull anchore/grype:latest docker pull anchore/grype:latest
docker run --rm -v /tmp/container.tar:/container.tar anchore/grype:latest /container.tar docker run --rm -v /tmp/container.tar:/container.tar anchore/grype:latest /container.tar
``` ```
- [ ] Collect the assets in a single directory, calculate their SHA-256 hashes, and sign them. - [ ] Collect the assets in a single directory, calculate their SHA-256 hashes, and sign them.
There is an `./dev_scripts/sign-assets.py` script to automate this task. * You can use `./dev_scripts/sign-assets.py`, if you want to automate this
task.
- [ ] Create a new **draft** release on GitHub and upload the macOS and Windows installers.
* Copy the release notes text from the template at [`docs/templates/release-notes`](https://github.com/freedomofpress/dangerzone/tree/main/docs/templates/)
* You can use `./dev_scripts/upload-asset.py`, if you want to upload an asset
using an access token.
- [ ] Upload the `container-$VERSION-i686.tar.gz` and `container-$VERSION-arm64.tar.gz` images that were created in the previous step
**Important:** Before running the script, make sure that it's the same container images as **Important:** Make sure that it's the same container images as the ones that
the ones that are shipped in other platforms (see our [Pre-release](#Pre-release) section) are shipped in other platforms (see our [Pre-release](#Pre-release) section)
```bash
# Sign all the assets
./dev_scripts/sign-assets.py ~/release-assets/$VERSION/github --version $VERSION
```
- [ ] Upload all the assets to the draft release on GitHub.
```bash
find ~/release-assets/$VERSION/github | xargs -n1 ./dev_scripts/upload-asset.py --token ~/token --draft
```
- [ ] Upload the detached signatures (.asc) and checksum file.
- [ ] Update the [Dangerzone website](https://github.com/freedomofpress/dangerzone.rocks) to link to the new installers. - [ ] Update the [Dangerzone website](https://github.com/freedomofpress/dangerzone.rocks) to link to the new installers.
- [ ] Update the brew cask release of Dangerzone with a [PR like this one](https://github.com/Homebrew/homebrew-cask/pull/116319) - [ ] Update the brew cask release of Dangerzone with a [PR like this one](https://github.com/Homebrew/homebrew-cask/pull/116319)
- [ ] Update version and download links in `README.md` - [ ] Update version and download links in `README.md`

View file

@ -16,6 +16,42 @@ DEFAULT_USER = "user"
DEFAULT_DRY = False DEFAULT_DRY = False
DEFAULT_DEV = False DEFAULT_DEV = False
DEFAULT_SHOW_DOCKERFILE = False DEFAULT_SHOW_DOCKERFILE = False
DEFAULT_DOWNLOAD_PYSIDE6 = False
PYSIDE6_VERSION = "6.7.1"
PYSIDE6_RPM = "python3-pyside6-{pyside6_version}-1.fc{fedora_version}.x86_64.rpm"
PYSIDE6_URL = (
"https://packages.freedom.press/yum-tools-prod/dangerzone/f{fedora_version}/%s"
% PYSIDE6_RPM
)
PYSIDE6_DL_MESSAGE = """\
Downloading PySide6 RPM from:
{pyside6_url}
into the following local path:
{pyside6_local_path}
The RPM is over 100 MB, so this operation may take a while...
"""
PYSIDE6_NOT_FOUND_ERROR = """\
The following package is not present in your system:
{pyside6_local_path}
You can build it locally and copy it in the expected path, following the instructions
in:
https://github.com/freedomofpress/python3-pyside6-rpm
Alternatively, you can rerun the command adding the '--download-pyside6' flag, which
will download it from:
{pyside6_url}
"""
# The Linux distributions that we currently support. # The Linux distributions that we currently support.
# FIXME: Add a version mapping to avoid mistakes. # FIXME: Add a version mapping to avoid mistakes.
@ -196,6 +232,11 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
""" """
DOCKERFILE_BUILD_FEDORA_39_DEPS = r"""
COPY {pyside6_rpm} /tmp/pyside6.rpm
RUN dnf install -y /tmp/pyside6.rpm
"""
DOCKERFILE_BUILD_FEDORA_DEPS = r""" DOCKERFILE_BUILD_FEDORA_DEPS = r"""
RUN dnf install -y mupdf thunar && dnf clean all RUN dnf install -y mupdf thunar && dnf clean all
@ -349,6 +390,74 @@ def get_files_in(*folders: list[str]) -> list[pathlib.Path]:
return files return files
class PySide6Manager:
"""Provision PySide6 RPMs in our Dangerzone environments.
This class holds all the logic around checking and downloading PySide RPMs. It can
check if the required RPM version is present under "/dist", and optionally download
it.
"""
def __init__(self, distro_name, distro_version):
if distro_name != "fedora":
raise RuntimeError("Managing PySide6 RPMs is available only in Fedora")
self.distro_name = distro_name
self.distro_version = distro_version
@property
def version(self):
"""The version of the PySide6 RPM."""
return PYSIDE6_VERSION
@property
def rpm_name(self):
"""The name of the PySide6 RPM."""
return PYSIDE6_RPM.format(
pyside6_version=self.version, fedora_version=self.distro_version
)
@property
def rpm_url(self):
"""The URL of the PySide6 RPM, as hosted in FPF's RPM repo."""
return PYSIDE6_URL.format(
pyside6_version=self.version,
fedora_version=self.distro_version,
)
@property
def rpm_local_path(self):
"""The local path where this script will look for the PySide6 RPM."""
return git_root() / "dist" / self.rpm_name
@property
def is_rpm_present(self):
"""Check if PySide6 RPM is present in the user's system."""
return self.rpm_local_path.exists()
def download_rpm(self):
"""Download PySide6 from FPF's RPM repo."""
print(
PYSIDE6_DL_MESSAGE.format(
pyside6_url=self.rpm_url,
pyside6_local_path=self.rpm_local_path,
),
file=sys.stderr,
)
try:
with (
urllib.request.urlopen(self.rpm_url) as r,
open(self.rpm_local_path, "wb") as f,
):
shutil.copyfileobj(r, f)
except:
# NOTE: We purposefully catch all exceptions, since we want to catch Ctrl-C
# as well.
print("Download interrupted, removing file", file=sys.stderr)
self.rpm_local_path.unlink()
raise
print("PySide6 was downloaded successfully", file=sys.stderr)
class Env: class Env:
"""A class that implements actions on Dangerzone environments""" """A class that implements actions on Dangerzone environments"""
@ -627,6 +736,7 @@ class Env:
def build( def build(
self, self,
show_dockerfile=DEFAULT_SHOW_DOCKERFILE, show_dockerfile=DEFAULT_SHOW_DOCKERFILE,
download_pyside6=DEFAULT_DOWNLOAD_PYSIDE6,
): ):
"""Build a Linux environment and install Dangerzone in it.""" """Build a Linux environment and install Dangerzone in it."""
build_dir = distro_build(self.distro, self.version) build_dir = distro_build(self.distro, self.version)
@ -639,6 +749,28 @@ class Env:
package = package_src.name package = package_src.name
package_dst = build_dir / package package_dst = build_dir / package
install_cmd = "dnf install -y" install_cmd = "dnf install -y"
# NOTE: For Fedora 39, we check if a PySide6 RPM package exists in
# the user's system. If not, we either throw an error or download it from
# FPF's repo, according to the user's choice.
if self.version == "39":
pyside6 = PySide6Manager(self.distro, self.version)
if not pyside6.is_rpm_present:
if download_pyside6:
pyside6.download_rpm()
else:
print(
PYSIDE6_NOT_FOUND_ERROR.format(
pyside6_local_path=pyside6.rpm_local_path,
pyside6_url=pyside6.rpm_url,
),
file=sys.stderr,
)
return 1
shutil.copy(pyside6.rpm_local_path, build_dir / pyside6.rpm_name)
install_deps = (
DOCKERFILE_BUILD_FEDORA_DEPS + DOCKERFILE_BUILD_FEDORA_39_DEPS
).format(pyside6_rpm=pyside6.rpm_name)
else: else:
install_deps = DOCKERFILE_BUILD_DEBIAN_DEPS install_deps = DOCKERFILE_BUILD_DEBIAN_DEPS
if self.distro == "ubuntu" and self.version in ("20.04", "focal"): if self.distro == "ubuntu" and self.version in ("20.04", "focal"):
@ -712,6 +844,7 @@ def env_build(args):
env = Env.from_args(args) env = Env.from_args(args)
return env.build( return env.build(
show_dockerfile=args.show_dockerfile, show_dockerfile=args.show_dockerfile,
download_pyside6=args.download_pyside6,
) )
@ -808,6 +941,12 @@ def parse_args():
action="store_true", action="store_true",
help="Do not build, only show the Dockerfile", help="Do not build, only show the Dockerfile",
) )
parser_build.add_argument(
"--download-pyside6",
default=DEFAULT_DOWNLOAD_PYSIDE6,
action="store_true",
help="Download PySide6 from FPF's RPM repo",
)
return parser.parse_args() return parser.parse_args()

View file

@ -1,67 +0,0 @@
#!/usr/bin/env python3
import pathlib
import subprocess
RELEASE_FILE = "RELEASE.md"
QA_FILE = "QA.md"
def git_root():
"""Get the root directory of the Git repo."""
# FIXME: Use a Git Python binding for this.
# FIXME: Make this work if called outside the repo.
path = (
subprocess.run(
["git", "rev-parse", "--show-toplevel"],
check=True,
stdout=subprocess.PIPE,
)
.stdout.decode()
.strip("\n")
)
return pathlib.Path(path)
def extract_checkboxes(filename):
headers = []
result = []
with open(filename, "r") as f:
lines = f.readlines()
current_level = 0
for line in lines:
line = line.rstrip()
# If it's a header, store it
if line.startswith("#"):
# Count number of # to determine header level
level = len(line) - len(line.lstrip("#"))
if level < current_level or not current_level:
headers.extend(["", line, ""])
current_level = level
elif level > current_level:
continue
else:
headers = ["", line, ""]
# If it's a checkbox
elif "- [ ]" in line or "- [x]" in line or "- [X]" in line:
# Print the last header if we haven't already
if headers:
result.extend(headers)
headers = []
current_level = 0
# If this is the "Do the QA tasks" line, recursively get QA tasks
if "Do the QA tasks" in line:
result.append(line)
qa_tasks = extract_checkboxes(git_root() / QA_FILE)
result.append(qa_tasks)
else:
result.append(line)
return "\n".join(result)
if __name__ == "__main__":
print(extract_checkboxes(git_root() / RELEASE_FILE))

View file

@ -3,49 +3,28 @@
import abc import abc
import argparse import argparse
import difflib import difflib
import json
import logging import logging
import re import re
import selectors import selectors
import subprocess import subprocess
import sys import sys
import urllib.request
from pathlib import Path
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
PYTHON_VERSION = "3.12"
EOL_PYTHON_URL = "https://endoflife.date/api/python.json"
CONTENT_QA = r"""## QA CONTENT_QA = r"""## QA
To ensure that new releases do not introduce regressions, and support existing To ensure that new releases do not introduce regressions, and support existing
and newer platforms, we have to test that the produced packages work as expected. and newer platforms, we have to do the following:
Check the following:
- [ ] Make sure that the tip of the `main` branch passes the CI tests. - [ ] Make sure that the tip of the `main` branch passes the CI tests.
- [ ] Make sure that the Apple account has a valid application password and has - [ ] Make sure that the Apple account has a valid application password and has
agreed to the latest Apple terms (see [macOS release](#macos-release) agreed to the latest Apple terms (see [macOS release](#macos-release)
section). section).
Because it is repetitive, we wrote a script to help with the QA.
It can run the tasks for you, pausing when it needs manual intervention.
You can run it with a command like:
```bash
poetry run ./dev_scripts/qa.py {distro}-{version}
```
### The checklist
- [ ] Create a test build in Windows and make sure it works: - [ ] Create a test build in Windows and make sure it works:
- [ ] Check if the suggested Python version is still supported. - [ ] Check if the suggested Python version is still supported.
- [ ] Create a new development environment with Poetry. - [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses - [ ] Build the container image and ensure the development environment uses
the new image. the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests. - [ ] Run the Dangerzone tests.
- [ ] Build and run the Dangerzone .exe - [ ] Build and run the Dangerzone .exe
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below). - [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
@ -54,7 +33,6 @@ poetry run ./dev_scripts/qa.py {distro}-{version}
- [ ] Create a new development environment with Poetry. - [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses - [ ] Build the container image and ensure the development environment uses
the new image. the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests. - [ ] Run the Dangerzone tests.
- [ ] Create and run an app bundle. - [ ] Create and run an app bundle.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below). - [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
@ -63,7 +41,6 @@ poetry run ./dev_scripts/qa.py {distro}-{version}
- [ ] Create a new development environment with Poetry. - [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses - [ ] Build the container image and ensure the development environment uses
the new image. the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests. - [ ] Run the Dangerzone tests.
- [ ] Create and run an app bundle. - [ ] Create and run an app bundle.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below). - [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
@ -72,7 +49,6 @@ poetry run ./dev_scripts/qa.py {distro}-{version}
- [ ] Create a new development environment with Poetry. - [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses - [ ] Build the container image and ensure the development environment uses
the new image. the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests. - [ ] Run the Dangerzone tests.
- [ ] Create a .deb package and install it system-wide. - [ ] Create a .deb package and install it system-wide.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below). - [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
@ -81,7 +57,6 @@ poetry run ./dev_scripts/qa.py {distro}-{version}
- [ ] Create a new development environment with Poetry. - [ ] Create a new development environment with Poetry.
- [ ] Build the container image and ensure the development environment uses - [ ] Build the container image and ensure the development environment uses
the new image. the new image.
- [ ] Download the OCR language data using `./install/common/download-tessdata.py`
- [ ] Run the Dangerzone tests. - [ ] Run the Dangerzone tests.
- [ ] Create an .rpm package and install it system-wide. - [ ] Create an .rpm package and install it system-wide.
- [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below). - [ ] Test some QA scenarios (see [Scenarios](#Scenarios) below).
@ -572,7 +547,7 @@ class Reference:
# Convert spaces to dashes # Convert spaces to dashes
anchor = anchor.replace(" ", "-") anchor = anchor.replace(" ", "-")
# Remove non-alphanumeric (except dash and underscore) # Remove non-alphanumeric (except dash and underscore)
anchor = re.sub("[^a-zA-Z-_]", "", anchor) anchor = re.sub("[^a-zA-Z\-_]", "", anchor)
return anchor return anchor
@ -591,8 +566,8 @@ class QABase(abc.ABC):
platforms = {} platforms = {}
REF_QA = Reference("QA.md", content=CONTENT_QA) REF_QA = Reference("RELEASE.md", content=CONTENT_QA)
REF_QA_SCENARIOS = Reference("QA.md", content=CONTENT_QA_SCENARIOS) REF_QA_SCENARIOS = Reference("RELEASE.md", content=CONTENT_QA_SCENARIOS)
# The following class method is available since Python 3.6. For more details, see: # The following class method is available since Python 3.6. For more details, see:
# https://docs.python.org/3.6/whatsnew/3.6.html#pep-487-simpler-customization-of-class-creation # https://docs.python.org/3.6/whatsnew/3.6.html#pep-487-simpler-customization-of-class-creation
@ -801,10 +776,6 @@ class QABase(abc.ABC):
self.prompt("Does it pass?", choices=["y", "n"]) self.prompt("Does it pass?", choices=["y", "n"])
logger.info("Successfully completed QA scenarios") logger.info("Successfully completed QA scenarios")
@task("Download Tesseract data", auto=True)
def download_tessdata(self):
self.run("python", str(Path("install", "common", "download-tessdata.py")))
@classmethod @classmethod
@abc.abstractmethod @abc.abstractmethod
def get_id(cls): def get_id(cls):
@ -831,40 +802,6 @@ class QAWindows(QABase):
while msvcrt.kbhit(): while msvcrt.kbhit():
msvcrt.getch() msvcrt.getch()
def get_latest_python_release(self):
with urllib.request.urlopen(EOL_PYTHON_URL) as f:
resp = f.read()
releases = json.loads(resp)
for release in releases:
if release["cycle"] == PYTHON_VERSION:
# Transform the Python version string (e.g., "3.12.7") into a list
# (e.g., [3, 12, 7]), and return it
return [int(num) for num in release["latest"].split(".")]
raise RuntimeError(
f"Could not find a Python release for version {PYTHON_VERSION}"
)
@QABase.task(
f"Install the latest version of Python {PYTHON_VERSION}", ref=REF_BUILD
)
def install_python(self):
logger.info("Getting latest Python release")
try:
latest_version = self.get_latest_python_release()
except Exception:
logger.error("Could not verify that the latest Python version is installed")
cur_version = list(sys.version_info[:3])
if latest_version > cur_version:
self.prompt(
f"You need to install the latest Python version ({latest_version})"
)
elif latest_version == cur_version:
logger.info(
f"Verified that the latest Python version ({latest_version}) is installed"
)
@QABase.task("Install and Run Docker Desktop", ref=REF_BUILD) @QABase.task("Install and Run Docker Desktop", ref=REF_BUILD)
def install_docker(self): def install_docker(self):
logger.info("Checking if Docker Desktop is installed and running") logger.info("Checking if Docker Desktop is installed and running")
@ -879,7 +816,7 @@ class QAWindows(QABase):
) )
def install_poetry(self): def install_poetry(self):
self.run("python", "-m", "pip", "install", "poetry") self.run("python", "-m", "pip", "install", "poetry")
self.run("poetry", "install", "--sync") self.run("poetry", "install")
@QABase.task("Build Dangerzone container image", ref=REF_BUILD, auto=True) @QABase.task("Build Dangerzone container image", ref=REF_BUILD, auto=True)
def build_image(self): def build_image(self):
@ -901,11 +838,9 @@ class QAWindows(QABase):
return "windows" return "windows"
def start(self): def start(self):
self.install_python()
self.install_docker() self.install_docker()
self.install_poetry() self.install_poetry()
self.build_image() self.build_image()
self.download_tessdata()
self.run_tests() self.run_tests()
self.build_dangerzone_exe() self.build_dangerzone_exe()
@ -980,6 +915,7 @@ class QALinux(QABase):
"--version", "--version",
self.VERSION, self.VERSION,
"build", "build",
"--download-pyside6",
) )
@classmethod @classmethod
@ -997,7 +933,6 @@ class QALinux(QABase):
def start(self): def start(self):
self.build_dev_image() self.build_dev_image()
self.build_container_image() self.build_container_image()
self.download_tessdata()
self.run_tests() self.run_tests()
self.build_package() self.build_package()
self.build_qa_image() self.build_qa_image()
@ -1070,14 +1005,14 @@ class QAFedora(QALinux):
) )
class QAFedora41(QAFedora):
VERSION = "41"
class QAFedora40(QAFedora): class QAFedora40(QAFedora):
VERSION = "40" VERSION = "40"
class QAFedora39(QAFedora):
VERSION = "39"
def parse_args(): def parse_args():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
prog=sys.argv[0], prog=sys.argv[0],