mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-05-06 13:31:50 +02:00
Compare commits
17 commits
1003b2cef8
...
60df4f7e35
Author | SHA1 | Date | |
---|---|---|---|
![]() |
60df4f7e35 | ||
![]() |
9fa3c80404 | ||
![]() |
4bf7f9cbb4 | ||
![]() |
fdc27c4d3b | ||
![]() |
23f5f96220 | ||
![]() |
5744215d99 | ||
![]() |
c89988654c | ||
![]() |
7eaa0cfe50 | ||
![]() |
9d69e3b261 | ||
![]() |
1d2a91e8c5 | ||
![]() |
82c29b2098 | ||
![]() |
ce5aca4ba1 | ||
![]() |
13f38cc8a9 | ||
![]() |
57df6fdfe5 | ||
![]() |
20354e7c11 | ||
![]() |
d722800a4b | ||
![]() |
4cfc633cdb |
20 changed files with 927 additions and 506 deletions
2
.github/ISSUE_TEMPLATE/bug_report_linux.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report_linux.yml
vendored
|
@ -36,7 +36,7 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Podman info
|
label: Podman info
|
||||||
description: |
|
description: |
|
||||||
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:
|
Please copy and paste the following commands in your terminal, and provide us with the output:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
podman version
|
podman version
|
||||||
|
|
3
.github/ISSUE_TEMPLATE/bug_report_macos.yml
vendored
3
.github/ISSUE_TEMPLATE/bug_report_macos.yml
vendored
|
@ -48,8 +48,7 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Docker info
|
label: Docker info
|
||||||
description: |
|
description: |
|
||||||
If the bug occurs during document conversion, or is otherwise related
|
Please copy and paste the following commands in your
|
||||||
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
|
||||||
|
|
|
@ -35,8 +35,7 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Docker info
|
label: Docker info
|
||||||
description: |
|
description: |
|
||||||
If the bug occurs during document conversion, or is otherwise related
|
Please copy and paste the following commands in your
|
||||||
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
|
||||||
|
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -47,8 +47,6 @@ 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
|
||||||
|
|
35
.github/workflows/check_pr.yml
vendored
Normal file
35
.github/workflows/check_pr.yml
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
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
19
.github/workflows/check_push.yml
vendored
|
@ -1,19 +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
|
|
41
.github/workflows/ci.yml
vendored
41
.github/workflows/ci.yml
vendored
|
@ -68,6 +68,12 @@ 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
|
||||||
|
@ -120,6 +126,13 @@ 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 }})"
|
||||||
|
@ -151,7 +164,15 @@ 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
|
||||||
|
@ -216,7 +237,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-${{ matrix.distro }}-${{ matrix.version }}.deb
|
name: dangerzone.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
|
||||||
|
@ -255,7 +276,7 @@ jobs:
|
||||||
- name: Download Dangerzone .deb
|
- name: Download Dangerzone .deb
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dangerzone-debian-bookworm.deb
|
name: dangerzone.deb
|
||||||
path: "deb_dist/"
|
path: "deb_dist/"
|
||||||
|
|
||||||
- name: Build end-user environment
|
- name: Build end-user environment
|
||||||
|
@ -284,7 +305,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
distro: ["fedora"]
|
distro: ["fedora"]
|
||||||
version: ["39", "40", "41"]
|
version: ["40", "41"]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
@ -318,6 +339,14 @@ 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.
|
||||||
|
@ -328,7 +357,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 --download-pyside6
|
build
|
||||||
|
|
||||||
- name: Run a test command
|
- name: Run a test command
|
||||||
run: |
|
run: |
|
||||||
|
@ -363,8 +392,6 @@ 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
|
||||||
|
|
7
.github/workflows/scan_released.yml
vendored
7
.github/workflows/scan_released.yml
vendored
|
@ -11,15 +11,16 @@ jobs:
|
||||||
include:
|
include:
|
||||||
- runs-on: ubuntu-latest
|
- runs-on: ubuntu-latest
|
||||||
arch: i686
|
arch: i686
|
||||||
- runs-on: macos-latest
|
# Do not scan Silicon mac for now to avoid masking release scan results for other plaforms.
|
||||||
arch: arm64
|
# - runs-on: macos-latest
|
||||||
|
# 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 | jq -r '.tag_name')
|
VERSION=$(curl https://api.github.com/repos/freedomofpress/dangerzone/releases/latest | grep "tag_name" | cut -d '"' -f 4)
|
||||||
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}
|
||||||
|
|
15
BUILD.md
15
BUILD.md
|
@ -260,11 +260,17 @@ 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
|
||||||
|
@ -308,18 +314,9 @@ 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
|
||||||
|
|
|
@ -12,6 +12,10 @@ 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))
|
||||||
|
|
||||||
## [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
|
||||||
|
|
35
INSTALL.md
35
INSTALL.md
|
@ -1,8 +1,21 @@
|
||||||
## 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
|
||||||
|
@ -18,7 +31,6 @@ 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)
|
||||||
|
|
||||||
|
@ -125,23 +137,6 @@ 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
Normal file
197
QA.md
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
## 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.
|
30
README.md
30
README.md
|
@ -6,33 +6,21 @@ Take potentially dangerous PDFs, office documents, or images and convert them to
|
||||||
|  | 
|
|  | 
|
||||||
|--|--|
|
|--|--|
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
_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
|
||||||
|
|
||||||
### MacOS
|
Follow the instructions for each platform:
|
||||||
- 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`
|
* [macOS](https://github.com/freedomofpress/dangerzone/blob/v0.8.0//INSTALL.md#macos)
|
||||||
|
* [Windows](https://github.com/freedomofpress/dangerzone/blob/v0.8.0//INSTALL.md#windows)
|
||||||
> **Note**: you will also need to install [Docker Desktop](https://www.docker.com/products/docker-desktop/).
|
* [Ubuntu 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
|
* [Debian Linux](https://github.com/freedomofpress/dangerzone/blob/v0.8.0/INSTALL.md#ubuntu-debian)
|
||||||
> create the secure environment.
|
* [Fedora Linux](https://github.com/freedomofpress/dangerzone/blob/v0.8.0/INSTALL.md#fedora)
|
||||||
|
* [Qubes OS (beta)](https://github.com/freedomofpress/dangerzone/blob/v0.8.0/INSTALL.md#qubes-os)
|
||||||
### Windows
|
* [Tails](https://github.com/freedomofpress/dangerzone/blob/v0.8.0/INSTALL.md#tails)
|
||||||
|
|
||||||
- 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
|
||||||
|
|
||||||
|
|
400
RELEASE.md
400
RELEASE.md
|
@ -1,21 +1,23 @@
|
||||||
# Release instructions
|
# Release instructions
|
||||||
|
|
||||||
This section documents the release process. Unless you're a dangerzone developer making a release, you'll probably never need to follow it.
|
This section documents how we currently release Dangerzone for the different distributions we support.
|
||||||
|
|
||||||
## Pre-release
|
## Pre-release
|
||||||
|
|
||||||
Before making a release, all of these should be complete:
|
Here is a list of tasks that should be done before issuing the release:
|
||||||
|
|
||||||
- [ ] Copy the checkboxes from these instructions onto a new issue and call it **QA and Release version \<VERSION\>**
|
- [ ] Create a new issue named **QA and Release for version \<VERSION\>**, to track the general progress.
|
||||||
|
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
|
||||||
|
|
||||||
|
@ -38,22 +40,12 @@ 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 an EOL version:
|
In case of the removal of a 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.
|
||||||
|
@ -62,192 +54,13 @@ 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
|
||||||
```
|
```
|
||||||
|
@ -263,6 +76,8 @@ 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:
|
||||||
|
@ -277,48 +92,85 @@ Once we are confident that the release will be out shortly, and doesn't need any
|
||||||
|
|
||||||
#### 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
|
|
||||||
3.11 to 3.12 , reinstall Poetry with `python3 -m pip install poetry`
|
- [ ] Checkout the dependencies, and clean your local copy:
|
||||||
* You can verify the correct Python version is used with `poetry debug info`
|
|
||||||
- [ ] Verify and checkout the git tag for this release
|
```bash
|
||||||
- [ ] Run `poetry install --sync`
|
|
||||||
- [ ] On the silicon mac, build the container image:
|
# 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
|
||||||
```
|
```
|
||||||
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.
|
|
||||||
- [ ] Run `poetry run ./install/macos/build-app.py`; this will make `dist/Dangerzone.app`
|
- [ ] Build the app bundle
|
||||||
|
|
||||||
|
```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))
|
||||||
- [ ] Run `poetry run ./install/macos/build-app.py --only-codesign`; this will make `dist/Dangerzone.dmg`
|
- [ ] Sign the application bundle, and notarize it
|
||||||
* 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.
|
You need to run this command as the account that has access to the code signing certificate
|
||||||
- [ ] Notarize it: `xcrun notarytool submit --wait --apple-id "<email>" --keychain-profile "dz-notarytool-release-key" dist/Dangerzone.dmg`
|
|
||||||
* You need to change the `<email>` in the above command with the email
|
This command assumes that you have created, and stored in the Keychain, an
|
||||||
associated with the Apple Developer ID.
|
application password associated with your Apple Developer ID, which will be
|
||||||
* This command assumes that you have created, and stored in the Keychain, an
|
used specifically for `notarytool`.
|
||||||
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`
|
|
||||||
|
|
||||||
This process ends up with the final file:
|
```bash
|
||||||
|
# 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
|
||||||
dist/Dangerzone.dmg
|
# from a terminal application.
|
||||||
```
|
xcrun notarytool submit ./dist/Dangerzone.dmg --apple-id $APPLE_ID --keychain-profile "dz-notarytool-release-key" --wait && xcrun stapler staple dist/Dangerzone.dmg
|
||||||
|
|
||||||
Rename `Dangerzone.dmg` to `Dangerzone-$VERSION.dmg`.
|
# Copy the .dmg to the assets folder
|
||||||
|
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
|
||||||
|
|
||||||
|
@ -332,8 +184,31 @@ The Windows release is performed in a Windows 11 virtual machine as opposed to a
|
||||||
|
|
||||||
#### Releasing and Signing
|
#### Releasing and Signing
|
||||||
|
|
||||||
- [ ] Verify and checkout the git tag for this release
|
- [ ] Checkout the dependencies, and clean your local copy:
|
||||||
- [ ] Run `poetry install --sync`
|
```bash
|
||||||
|
# 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.
|
||||||
|
@ -365,21 +240,15 @@ 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"
|
||||||
|
|
||||||
```sh
|
# Create a .deb
|
||||||
python3 ./install/common/build-image.py
|
./dev_scripts/env.py --distro debian --version bookworm run --dev bash -c "cd dangerzone && ./install/linux/build-deb.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
|
||||||
|
@ -398,22 +267,12 @@ 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:
|
# Build the latest container (skip if already built):
|
||||||
|
./dev_scripts/env.py --distro fedora --version 41 run --dev bash -c "cd dangerzone && poetry run ./install/common/build-image.py"
|
||||||
|
|
||||||
```sh
|
# Create a .rpm:
|
||||||
python3 ./install/common/build-image.py
|
./dev_scripts/env.py --distro fedora --version 41 run --dev bash -c "cd dangerzone && ./install/linux/build-rpm.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
|
||||||
|
@ -424,7 +283,7 @@ Publish the .rpm under `./dist` to the
|
||||||
Create a .rpm for Qubes:
|
Create a .rpm for Qubes:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./install/linux/build-rpm.py --qubes
|
./dev_scripts/env.py --distro fedora --version 41 run --dev bash -c "cd dangerzone && ./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)
|
||||||
|
@ -432,36 +291,37 @@ repo.
|
||||||
|
|
||||||
## Publishing the Release
|
## Publishing the Release
|
||||||
|
|
||||||
To publish the release:
|
To publish the release, you can follow these steps:
|
||||||
|
|
||||||
- [ ] Create an archive of the Dangerzone source in `tar.gz` format:
|
- [ ] Create an archive of the Dangerzone source in `tar.gz` format:
|
||||||
* You can use the following command:
|
```bash
|
||||||
|
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.
|
||||||
* You can use `./dev_scripts/sign-assets.py`, if you want to automate this
|
There is an `./dev_scripts/sign-assets.py` script to automate this task.
|
||||||
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:** Make sure that it's the same container images as the ones that
|
**Important:** Before running the script, make sure that it's the same container images as
|
||||||
are shipped in other platforms (see our [Pre-release](#Pre-release) section)
|
the ones that 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`
|
||||||
|
|
|
@ -16,42 +16,6 @@ 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.
|
||||||
|
@ -232,11 +196,6 @@ 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
|
||||||
|
|
||||||
|
@ -390,74 +349,6 @@ 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"""
|
||||||
|
|
||||||
|
@ -736,7 +627,6 @@ 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)
|
||||||
|
@ -749,28 +639,6 @@ 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"):
|
||||||
|
@ -844,7 +712,6 @@ 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,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -941,12 +808,6 @@ 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()
|
||||||
|
|
||||||
|
|
254
dev_scripts/generate-release-notes.py
Executable file
254
dev_scripts/generate-release-notes.py
Executable file
|
@ -0,0 +1,254 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import asyncio
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
REPOSITORY = "https://github.com/freedomofpress/dangerzone/"
|
||||||
|
TEMPLATE = "- {title} ([#{number}]({url}))"
|
||||||
|
|
||||||
|
|
||||||
|
def parse_version(version: str) -> Tuple[int, int]:
|
||||||
|
"""Extract major.minor from version string, ignoring patch"""
|
||||||
|
match = re.match(r"v?(\d+)\.(\d+)", version)
|
||||||
|
if not match:
|
||||||
|
raise ValueError(f"Invalid version format: {version}")
|
||||||
|
return (int(match.group(1)), int(match.group(2)))
|
||||||
|
|
||||||
|
|
||||||
|
async def get_last_minor_release(
|
||||||
|
client: httpx.AsyncClient, owner: str, repo: str
|
||||||
|
) -> Optional[str]:
|
||||||
|
"""Get the latest minor release date (ignoring patches)"""
|
||||||
|
response = await client.get(f"https://api.github.com/repos/{owner}/{repo}/releases")
|
||||||
|
response.raise_for_status()
|
||||||
|
releases = response.json()
|
||||||
|
|
||||||
|
if not releases:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Get the latest minor version by comparing major.minor numbers
|
||||||
|
current_version = parse_version(releases[0]["tag_name"])
|
||||||
|
latest_date = None
|
||||||
|
|
||||||
|
for release in releases:
|
||||||
|
try:
|
||||||
|
version = parse_version(release["tag_name"])
|
||||||
|
if version < current_version:
|
||||||
|
latest_date = release["published_at"]
|
||||||
|
break
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return latest_date
|
||||||
|
|
||||||
|
|
||||||
|
async def get_issue_details(
|
||||||
|
client: httpx.AsyncClient, owner: str, repo: str, issue_number: int
|
||||||
|
) -> Optional[dict]:
|
||||||
|
"""Get issue title and number if it exists"""
|
||||||
|
response = await client.get(
|
||||||
|
f"https://api.github.com/repos/{owner}/{repo}/issues/{issue_number}"
|
||||||
|
)
|
||||||
|
if response.is_success:
|
||||||
|
data = response.json()
|
||||||
|
return {
|
||||||
|
"title": data["title"],
|
||||||
|
"number": data["number"],
|
||||||
|
"url": data["html_url"],
|
||||||
|
}
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def extract_issue_number(pr_body: Optional[str]) -> Optional[int]:
|
||||||
|
"""Extract issue number from PR body looking for common formats like 'Fixes #123' or 'Closes #123'"""
|
||||||
|
if not pr_body:
|
||||||
|
return None
|
||||||
|
|
||||||
|
patterns = [
|
||||||
|
r"(?:closes|fixes|resolves)\s*#(\d+)",
|
||||||
|
r"(?:close|fix|resolve)\s*#(\d+)",
|
||||||
|
]
|
||||||
|
|
||||||
|
for pattern in patterns:
|
||||||
|
match = re.search(pattern, pr_body.lower())
|
||||||
|
if match:
|
||||||
|
return int(match.group(1))
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def verify_commit_in_master(
|
||||||
|
client: httpx.AsyncClient, owner: str, repo: str, commit_id: str
|
||||||
|
) -> bool:
|
||||||
|
"""Verify if a commit exists in master"""
|
||||||
|
response = await client.get(
|
||||||
|
f"https://api.github.com/repos/{owner}/{repo}/commits/{commit_id}"
|
||||||
|
)
|
||||||
|
return response.is_success and response.json().get("commit") is not None
|
||||||
|
|
||||||
|
|
||||||
|
async def process_issue_events(
|
||||||
|
client: httpx.AsyncClient, owner: str, repo: str, issue: Dict
|
||||||
|
) -> Optional[Dict]:
|
||||||
|
"""Process events for a single issue"""
|
||||||
|
events_response = await client.get(f"{issue['url']}/events")
|
||||||
|
if not events_response.is_success:
|
||||||
|
return None
|
||||||
|
|
||||||
|
for event in events_response.json():
|
||||||
|
if event["event"] == "closed" and event.get("commit_id"):
|
||||||
|
if await verify_commit_in_master(client, owner, repo, event["commit_id"]):
|
||||||
|
return {
|
||||||
|
"title": issue["title"],
|
||||||
|
"number": issue["number"],
|
||||||
|
"url": issue["html_url"],
|
||||||
|
}
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def get_closed_issues(
|
||||||
|
client: httpx.AsyncClient, owner: str, repo: str, since: str
|
||||||
|
) -> List[Dict]:
|
||||||
|
"""Get issues closed by commits to master since the given date"""
|
||||||
|
response = await client.get(
|
||||||
|
f"https://api.github.com/repos/{owner}/{repo}/issues",
|
||||||
|
params={
|
||||||
|
"state": "closed",
|
||||||
|
"sort": "updated",
|
||||||
|
"direction": "desc",
|
||||||
|
"since": since,
|
||||||
|
"per_page": 100,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
tasks = []
|
||||||
|
since_date = datetime.strptime(since, "%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
|
||||||
|
for issue in response.json():
|
||||||
|
if "pull_request" in issue:
|
||||||
|
continue
|
||||||
|
|
||||||
|
closed_at = datetime.strptime(issue["closed_at"], "%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
if closed_at <= since_date:
|
||||||
|
continue
|
||||||
|
|
||||||
|
tasks.append(process_issue_events(client, owner, repo, issue))
|
||||||
|
|
||||||
|
results = await asyncio.gather(*tasks)
|
||||||
|
return [r for r in results if r is not None]
|
||||||
|
|
||||||
|
|
||||||
|
async def process_pull_request(
|
||||||
|
client: httpx.AsyncClient,
|
||||||
|
owner: str,
|
||||||
|
repo: str,
|
||||||
|
pr: Dict,
|
||||||
|
closed_issues: List[Dict],
|
||||||
|
) -> Optional[str]:
|
||||||
|
"""Process a single pull request"""
|
||||||
|
issue_number = extract_issue_number(pr.get("body"))
|
||||||
|
if issue_number:
|
||||||
|
issue = await get_issue_details(client, owner, repo, issue_number)
|
||||||
|
if issue:
|
||||||
|
if not any(i["number"] == issue["number"] for i in closed_issues):
|
||||||
|
return TEMPLATE.format(**issue)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return TEMPLATE.format(title=pr["title"], number=pr["number"], url=pr["html_url"])
|
||||||
|
|
||||||
|
|
||||||
|
async def get_changes_since_last_release(
|
||||||
|
owner: str, repo: str, token: Optional[str] = None
|
||||||
|
) -> List[str]:
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/vnd.github.v3+json",
|
||||||
|
}
|
||||||
|
if token:
|
||||||
|
headers["Authorization"] = f"token {token}"
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
"Warning: No token provided. API rate limiting may occur.", file=sys.stderr
|
||||||
|
)
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(headers=headers, timeout=30.0) as client:
|
||||||
|
# Get the date of last minor release
|
||||||
|
since = await get_last_minor_release(client, owner, repo)
|
||||||
|
if not since:
|
||||||
|
return []
|
||||||
|
|
||||||
|
changes = []
|
||||||
|
|
||||||
|
# Get issues closed by commits to master
|
||||||
|
closed_issues = await get_closed_issues(client, owner, repo, since)
|
||||||
|
changes.extend([TEMPLATE.format(**issue) for issue in closed_issues])
|
||||||
|
|
||||||
|
# Get merged PRs
|
||||||
|
response = await client.get(
|
||||||
|
f"https://api.github.com/repos/{owner}/{repo}/pulls",
|
||||||
|
params={
|
||||||
|
"state": "closed",
|
||||||
|
"sort": "updated",
|
||||||
|
"direction": "desc",
|
||||||
|
"per_page": 100,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
# Process PRs in parallel
|
||||||
|
pr_tasks = []
|
||||||
|
for pr in response.json():
|
||||||
|
if not pr["merged_at"]:
|
||||||
|
continue
|
||||||
|
if since and pr["merged_at"] <= since:
|
||||||
|
break
|
||||||
|
|
||||||
|
pr_tasks.append(
|
||||||
|
process_pull_request(client, owner, repo, pr, closed_issues)
|
||||||
|
)
|
||||||
|
|
||||||
|
pr_results = await asyncio.gather(*pr_tasks)
|
||||||
|
changes.extend([r for r in pr_results if r is not None])
|
||||||
|
|
||||||
|
return changes
|
||||||
|
|
||||||
|
|
||||||
|
async def main_async():
|
||||||
|
parser = argparse.ArgumentParser(description="Generate release notes from GitHub")
|
||||||
|
parser.add_argument("--token", "-t", help="the file path to the GitHub API token")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
token = None
|
||||||
|
if args.token:
|
||||||
|
with open(args.token) as f:
|
||||||
|
token = f.read().strip()
|
||||||
|
try:
|
||||||
|
url_path = REPOSITORY.rstrip("/").split("github.com/")[1]
|
||||||
|
owner, repo = url_path.split("/")[-2:]
|
||||||
|
except (ValueError, IndexError):
|
||||||
|
print("Error: Invalid GitHub URL", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
notes = await get_changes_since_last_release(owner, repo, token)
|
||||||
|
print("\n".join(notes))
|
||||||
|
except httpx.HTTPError as e:
|
||||||
|
print(f"Error: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
asyncio.run(main_async())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
67
dev_scripts/generate-release-tasks.py
Executable file
67
dev_scripts/generate-release-tasks.py
Executable file
|
@ -0,0 +1,67 @@
|
||||||
|
#!/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))
|
|
@ -3,28 +3,49 @@
|
||||||
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 do the following:
|
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 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).
|
||||||
|
@ -33,6 +54,7 @@ and newer platforms, we have to do the following:
|
||||||
- [ ] 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).
|
||||||
|
@ -41,6 +63,7 @@ and newer platforms, we have to do the following:
|
||||||
- [ ] 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).
|
||||||
|
@ -49,6 +72,7 @@ and newer platforms, we have to do the following:
|
||||||
- [ ] 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).
|
||||||
|
@ -57,6 +81,7 @@ and newer platforms, we have to do the following:
|
||||||
- [ ] 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).
|
||||||
|
@ -547,7 +572,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
|
||||||
|
|
||||||
|
@ -566,8 +591,8 @@ class QABase(abc.ABC):
|
||||||
|
|
||||||
platforms = {}
|
platforms = {}
|
||||||
|
|
||||||
REF_QA = Reference("RELEASE.md", content=CONTENT_QA)
|
REF_QA = Reference("QA.md", content=CONTENT_QA)
|
||||||
REF_QA_SCENARIOS = Reference("RELEASE.md", content=CONTENT_QA_SCENARIOS)
|
REF_QA_SCENARIOS = Reference("QA.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
|
||||||
|
@ -776,6 +801,10 @@ 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):
|
||||||
|
@ -802,6 +831,40 @@ 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")
|
||||||
|
@ -816,7 +879,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")
|
self.run("poetry", "install", "--sync")
|
||||||
|
|
||||||
@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):
|
||||||
|
@ -838,9 +901,11 @@ 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()
|
||||||
|
|
||||||
|
@ -915,7 +980,6 @@ class QALinux(QABase):
|
||||||
"--version",
|
"--version",
|
||||||
self.VERSION,
|
self.VERSION,
|
||||||
"build",
|
"build",
|
||||||
"--download-pyside6",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -933,6 +997,7 @@ 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()
|
||||||
|
@ -1005,14 +1070,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],
|
||||||
|
|
92
poetry.lock
generated
92
poetry.lock
generated
|
@ -11,6 +11,28 @@ files = [
|
||||||
{file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"},
|
{file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyio"
|
||||||
|
version = "4.6.2.post1"
|
||||||
|
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.9"
|
||||||
|
files = [
|
||||||
|
{file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"},
|
||||||
|
{file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""}
|
||||||
|
idna = ">=2.8"
|
||||||
|
sniffio = ">=1.1"
|
||||||
|
typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
|
||||||
|
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"]
|
||||||
|
trio = ["trio (>=0.26.1)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "appdirs"
|
name = "appdirs"
|
||||||
version = "1.4.4"
|
version = "1.4.4"
|
||||||
|
@ -404,6 +426,63 @@ files = [
|
||||||
[package.extras]
|
[package.extras]
|
||||||
test = ["pytest (>=6)"]
|
test = ["pytest (>=6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h11"
|
||||||
|
version = "0.14.0"
|
||||||
|
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
|
||||||
|
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpcore"
|
||||||
|
version = "1.0.7"
|
||||||
|
description = "A minimal low-level HTTP client."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"},
|
||||||
|
{file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
certifi = "*"
|
||||||
|
h11 = ">=0.13,<0.15"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
asyncio = ["anyio (>=4.0,<5.0)"]
|
||||||
|
http2 = ["h2 (>=3,<5)"]
|
||||||
|
socks = ["socksio (==1.*)"]
|
||||||
|
trio = ["trio (>=0.22.0,<1.0)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpx"
|
||||||
|
version = "0.27.2"
|
||||||
|
description = "The next generation HTTP client."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"},
|
||||||
|
{file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
anyio = "*"
|
||||||
|
certifi = "*"
|
||||||
|
httpcore = "==1.*"
|
||||||
|
idna = "*"
|
||||||
|
sniffio = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
brotli = ["brotli", "brotlicffi"]
|
||||||
|
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
|
||||||
|
http2 = ["h2 (>=3,<5)"]
|
||||||
|
socks = ["socksio (==1.*)"]
|
||||||
|
zstd = ["zstandard (>=0.18.0)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.10"
|
version = "3.10"
|
||||||
|
@ -991,6 +1070,17 @@ files = [
|
||||||
{file = "shiboken6-6.8.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:b11e750e696bb565d897e0f5836710edfb86bd355f87b09988bd31b2aad404d3"},
|
{file = "shiboken6-6.8.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:b11e750e696bb565d897e0f5836710edfb86bd355f87b09988bd31b2aad404d3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sniffio"
|
||||||
|
version = "1.3.1"
|
||||||
|
description = "Sniff out which async library your code is running under"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
|
||||||
|
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strip-ansi"
|
name = "strip-ansi"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -1099,4 +1189,4 @@ type = ["pytest-mypy"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.9,<3.13"
|
python-versions = ">=3.9,<3.13"
|
||||||
content-hash = "44356eaeeb3dbe23b922413ee68f8c73c6ce8ebbdee8a80afecb410e060d0382"
|
content-hash = "5d1ff28aa04c3a814280e55c0b2a307efe5ca953cd4cb281056c35fd2e53fdf0"
|
||||||
|
|
|
@ -57,6 +57,9 @@ pytest-rerunfailures = "^14.0"
|
||||||
[tool.poetry.group.container.dependencies]
|
[tool.poetry.group.container.dependencies]
|
||||||
pymupdf = "1.24.11" # Last version to support python 3.8 (needed for Ubuntu Focal support)
|
pymupdf = "1.24.11" # Last version to support python 3.8 (needed for Ubuntu Focal support)
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
httpx = "^0.27.2"
|
||||||
|
|
||||||
[tool.isort]
|
[tool.isort]
|
||||||
profile = "black"
|
profile = "black"
|
||||||
skip_gitignore = true
|
skip_gitignore = true
|
||||||
|
|
Loading…
Reference in a new issue