Compare commits

...

7 commits

Author SHA1 Message Date
Alex Pyrgiotis
1ed1dcee6b
WIP: Doit 2024-12-03 22:47:19 +02:00
Alex Pyrgiotis
57973b8a2e
Update our release instructions 2024-12-02 21:15:34 +02:00
Alex Pyrgiotis
ab6d9ba1fd
container: Revamp container image installation
Revamp the container image installation process in a way that does not
involve using image IDs. We don't want to rely on image IDs anymore,
since they are brittle (see
https://github.com/freedomofpress/dangerzone/issues/933). Instead, we
use image tags, as provided in the `image-id.txt` file.  This allows us
to check fast if an image is up to date, and we no longer need to
maintain multiple image IDs from various container runtimes.

Refs #933
Refs #988
Fixes #1020
2024-12-02 21:15:34 +02:00
Alex Pyrgiotis
8793871ffb
Build and tag Dangerzone images
Build Dangerzone images and tag them with a unique ID that stems from
the Git reop. Note that using tags as image IDs instead of regular image
IDs breaks the current Dangerzone expectations, but this will be
addressed in subsequent commits.
2024-12-02 21:15:34 +02:00
Alex Pyrgiotis
eb560b8e7f
container: Factor out loading an image tarball 2024-12-02 21:15:34 +02:00
Alex Pyrgiotis
587cb6d40e
container: Manipulate Dangerzone image tags
Add the following methods that allow the `Container` isolation provider
to work with tags for the Dangerzone image:
* `list_image_tag()`
* `delete_image_tag()`
* `add_image_tag()`
2024-12-02 21:15:34 +02:00
Alex Pyrgiotis
5ac1288277
Move container-specific method from base class
Move the `is_runtime_available()` method from the base
`IsolationProvider` class, and into the `Dummy` provider class. This
method was originally defined in the base class, in order to be mocked
in our tests for the `Dummy` provider. There's no reason for the `Qubes`
class to have it though, so we can just move it to the `Dummy` provider.
2024-12-02 21:15:34 +02:00
16 changed files with 627 additions and 111 deletions

View file

@ -74,6 +74,8 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get current date - name: Get current date
id: date id: date

View file

@ -48,6 +48,8 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get current date - name: Get current date
id: date id: date
@ -245,7 +247,7 @@ jobs:
install-deb: install-deb:
name: "install-deb (${{ matrix.distro }} ${{ matrix.version }})" name: "install-deb (${{ matrix.distro }} ${{ matrix.version }})"
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
- build-deb - build-deb
strategy: strategy:
matrix: matrix:

View file

@ -14,6 +14,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install container build dependencies - name: Install container build dependencies
run: sudo apt install pipx && pipx install poetry run: sudo apt install pipx && pipx install poetry
- name: Build container image - name: Build container image

1
.gitignore vendored
View file

@ -149,3 +149,4 @@ share/container.tar
share/container.tar.gz share/container.tar.gz
share/image-id.txt share/image-id.txt
container/container-pip-requirements.txt container/container-pip-requirements.txt
.doit.db.db

View file

@ -141,9 +141,10 @@ Close the Dangerzone application and get the container image for that
version. For example: version. For example:
``` ```
$ docker images dangerzone.rocks/dangerzone:latest $ docker images dangerzone.rocks/dangerzone
REPOSITORY TAG IMAGE ID CREATED SIZE REPOSITORY TAG IMAGE ID CREATED SIZE
dangerzone.rocks/dangerzone latest <image ID> <date> <size> dangerzone.rocks/dangerzone latest <image ID> <date> <size>
dangerzone.rocks/dangerzone <tag> <image ID> <date> <size>
``` ```
Then run the version under QA and ensure that the settings remain changed. Then run the version under QA and ensure that the settings remain changed.
@ -152,9 +153,10 @@ Afterwards check that new docker image was installed by running the same command
and seeing the following differences: and seeing the following differences:
``` ```
$ docker images dangerzone.rocks/dangerzone:latest $ docker images dangerzone.rocks/dangerzone
REPOSITORY TAG IMAGE ID CREATED SIZE REPOSITORY TAG IMAGE ID CREATED SIZE
dangerzone.rocks/dangerzone latest <different ID> <newer date> <different size> dangerzone.rocks/dangerzone latest <different ID> <newer date> <different size>
dangerzone.rocks/dangerzone <other tag> <different ID> <newer date> <different size>
``` ```
#### 4. Dangerzone successfully installs the container image #### 4. Dangerzone successfully installs the container image
@ -280,7 +282,7 @@ Once we are confident that the release will be out shortly, and doesn't need any
``` ```
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. 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` - [ ] Run `poetry run ./install/macos/build-app.py`; this will make `dist/Dangerzone.app`
- [ ] Make sure that the build application works with the containerd graph - [ ] Make sure that the built 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` - [ ] Run `poetry run ./install/macos/build-app.py --only-codesign`; this will make `dist/Dangerzone.dmg`
* You need to run this command as the account that has access to the code signing certificate * You need to run this command as the account that has access to the code signing certificate
@ -326,9 +328,6 @@ The Windows release is performed in a Windows 11 virtual machine as opposed to a
- [ ] 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.
> Also, don't forget to add the supplementary image ID (see
> [#933](https://github.com/freedomofpress/dangerzone/issues/933)) in
> `share/image-id.txt`)
- [ ] Run `poetry run .\install\windows\build-app.bat` - [ ] Run `poetry run .\install\windows\build-app.bat`
- [ ] When you're done you will have `dist\Dangerzone.msi` - [ ] When you're done you will have `dist\Dangerzone.msi`

View file

@ -500,6 +500,7 @@ class WaitingWidgetContainer(WaitingWidget):
error: Optional[str] = None error: Optional[str] = None
try: try:
assert isinstance(self.dangerzone.isolation_provider, (Dummy, Container))
self.dangerzone.isolation_provider.is_runtime_available() self.dangerzone.isolation_provider.is_runtime_available()
except NoContainerTechException as e: except NoContainerTechException as e:
log.error(str(e)) log.error(str(e))

View file

@ -93,10 +93,6 @@ class IsolationProvider(ABC):
else: else:
self.proc_stderr = subprocess.DEVNULL self.proc_stderr = subprocess.DEVNULL
@staticmethod
def is_runtime_available() -> bool:
return True
@abstractmethod @abstractmethod
def install(self) -> bool: def install(self) -> bool:
pass pass

View file

@ -1,11 +1,12 @@
import gzip import gzip
import json
import logging import logging
import os import os
import platform import platform
import shlex import shlex
import shutil import shutil
import subprocess import subprocess
from typing import List, Tuple from typing import Dict, List, Tuple
from ..document import Document from ..document import Document
from ..util import get_resource_path, get_subprocess_startupinfo from ..util import get_resource_path, get_subprocess_startupinfo
@ -155,16 +156,81 @@ class Container(IsolationProvider):
return security_args return security_args
@staticmethod @staticmethod
def install() -> bool: def list_image_tags() -> Dict[str, str]:
""" """Get the tags of all loaded Dangerzone images.
Make sure the podman container is installed. Linux only.
"""
if Container.is_container_installed():
return True
# Load the container into podman This method returns a mapping of image tags to image IDs, for all Dangerzone
images. This can be useful when we want to find which are the local image tags,
and which image ID does the "latest" tag point to.
"""
images = json.loads(
subprocess.check_output(
[
Container.get_runtime(),
"image",
"list",
"--format",
"json",
Container.CONTAINER_NAME,
],
text=True,
startupinfo=get_subprocess_startupinfo(),
)
)
# Grab every image name and associate it with an image ID.
tags = {}
for image in images:
for name in image["Names"]:
tag = name.split(":")[1]
tags[tag] = image["Id"]
return tags
@staticmethod
def delete_image_tag(tag: str) -> None:
"""Delete a Dangerzone image tag."""
name = Container.CONTAINER_NAME + ":" + tag
log.warning(f"Deleting old container image: {name}")
try:
subprocess.check_output(
[Container.get_runtime(), "rmi", "--force", name],
startupinfo=get_subprocess_startupinfo(),
)
except Exception as e:
log.warning(
f"Couldn't delete old container image '{name}', so leaving it there."
f" Original error: {e}"
)
@staticmethod
def add_image_tag(cur_tag: str, new_tag: str) -> None:
"""Add a tag to an existing Dangerzone image."""
cur_image_name = Container.CONTAINER_NAME + ":" + cur_tag
new_image_name = Container.CONTAINER_NAME + ":" + new_tag
subprocess.check_output(
[
Container.get_runtime(),
"tag",
cur_image_name,
new_image_name,
],
startupinfo=get_subprocess_startupinfo(),
)
log.info(
f"Successfully tagged container image '{cur_image_name}' as '{new_image_name}'"
)
@staticmethod
def get_expected_tag() -> str:
"""Get the tag of the Dangerzone image tarball from the image-id.txt file."""
with open(get_resource_path("image-id.txt")) as f:
return f.read().strip()
@staticmethod
def load_image_tarball() -> None:
log.info("Installing Dangerzone container image...") log.info("Installing Dangerzone container image...")
p = subprocess.Popen( p = subprocess.Popen(
[Container.get_runtime(), "load"], [Container.get_runtime(), "load"],
stdin=subprocess.PIPE, stdin=subprocess.PIPE,
@ -191,10 +257,54 @@ class Container(IsolationProvider):
f"Could not install container image: {error}" f"Could not install container image: {error}"
) )
if not Container.is_container_installed(raise_on_error=True): log.info("Successfully installed container image from")
return False
log.info("Container image installed") @staticmethod
def install() -> bool:
"""Install the container image tarball, or verify that it's already installed.
Perform the following actions:
1. Get the tags of any locally available images that match Dangerzone's image
name.
2. Get the expected image tag from the image-id.txt file.
- If this tag is present in the local images, and that image is also tagged
as "latest", then we can return.
- Else, prune the older container images and continue.
3. Load the image tarball and make sure it matches the expected tag.
4. Tag that image as "latest", and mark the installation as finished.
"""
old_tags = Container.list_image_tags()
expected_tag = Container.get_expected_tag()
if expected_tag not in old_tags:
# Prune older container images.
log.info(
f"Could not find a Dangerzone container image with tag '{expected_tag}'"
)
for tag in old_tags.keys():
Container.delete_image_tag(tag)
elif old_tags[expected_tag] != old_tags.get("latest"):
log.info(f"The expected tag '{expected_tag}' is not the latest one")
Container.add_image_tag(expected_tag, "latest")
return True
else:
return True
# Load the image tarball into the container runtime.
Container.load_image_tarball()
# Check that the container image has the expected image tag.
# See https://github.com/freedomofpress/dangerzone/issues/988 for an example
# where this was not the case.
new_tags = Container.list_image_tags()
if expected_tag not in new_tags:
raise ImageNotPresentException(
f"Could not find expected tag '{expected_tag}' after loading the"
" container image tarball"
)
# Mark the expected tag as "latest".
Container.add_image_tag(expected_tag, "latest")
return True return True
@staticmethod @staticmethod
@ -213,58 +323,6 @@ class Container(IsolationProvider):
raise NotAvailableContainerTechException(runtime_name, stderr.decode()) raise NotAvailableContainerTechException(runtime_name, stderr.decode())
return True return True
@staticmethod
def is_container_installed(raise_on_error: bool = False) -> bool:
"""
See if the container is installed.
"""
# Get the image id
with open(get_resource_path("image-id.txt")) as f:
expected_image_ids = f.read().strip().split()
# See if this image is already installed
installed = False
found_image_id = subprocess.check_output(
[
Container.get_runtime(),
"image",
"list",
"--format",
"{{.ID}}",
Container.CONTAINER_NAME,
],
text=True,
startupinfo=get_subprocess_startupinfo(),
)
found_image_id = found_image_id.strip()
if found_image_id in expected_image_ids:
installed = True
elif found_image_id == "":
if raise_on_error:
raise ImageNotPresentException(
"Image is not listed after installation. Bailing out."
)
else:
msg = (
f"{Container.CONTAINER_NAME} images found, but IDs do not match."
f" Found: {found_image_id}, Expected: {','.join(expected_image_ids)}"
)
if raise_on_error:
raise ImageNotPresentException(msg)
log.info(msg)
log.info("Deleting old dangerzone container image")
try:
subprocess.check_output(
[Container.get_runtime(), "rmi", "--force", found_image_id],
startupinfo=get_subprocess_startupinfo(),
)
except Exception:
log.warning("Couldn't delete old container image, so leaving it there")
return installed
def doc_to_pixels_container_name(self, document: Document) -> str: def doc_to_pixels_container_name(self, document: Document) -> str:
"""Unique container name for the doc-to-pixels phase.""" """Unique container name for the doc-to-pixels phase."""
return f"dangerzone-doc-to-pixels-{document.id}" return f"dangerzone-doc-to-pixels-{document.id}"

View file

@ -39,6 +39,10 @@ class Dummy(IsolationProvider):
def install(self) -> bool: def install(self) -> bool:
return True return True
@staticmethod
def is_runtime_available() -> bool:
return True
def start_doc_to_pixels_proc(self, document: Document) -> subprocess.Popen: def start_doc_to_pixels_proc(self, document: Document) -> subprocess.Popen:
cmd = [ cmd = [
sys.executable, sys.executable,

View file

@ -108,9 +108,10 @@ Close the Dangerzone application and get the container image for that
version. For example: version. For example:
``` ```
$ docker images dangerzone.rocks/dangerzone:latest $ docker images dangerzone.rocks/dangerzone
REPOSITORY TAG IMAGE ID CREATED SIZE REPOSITORY TAG IMAGE ID CREATED SIZE
dangerzone.rocks/dangerzone latest <image ID> <date> <size> dangerzone.rocks/dangerzone latest <image ID> <date> <size>
dangerzone.rocks/dangerzone <tag> <image ID> <date> <size>
``` ```
Then run the version under QA and ensure that the settings remain changed. Then run the version under QA and ensure that the settings remain changed.
@ -119,9 +120,10 @@ Afterwards check that new docker image was installed by running the same command
and seeing the following differences: and seeing the following differences:
``` ```
$ docker images dangerzone.rocks/dangerzone:latest $ docker images dangerzone.rocks/dangerzone
REPOSITORY TAG IMAGE ID CREATED SIZE REPOSITORY TAG IMAGE ID CREATED SIZE
dangerzone.rocks/dangerzone latest <different ID> <newer date> <different size> dangerzone.rocks/dangerzone latest <different ID> <newer date> <different size>
dangerzone.rocks/dangerzone <other tag> <different ID> <newer date> <different size>
``` ```
#### 4. Dangerzone successfully installs the container image #### 4. Dangerzone successfully installs the container image

377
dodo.py Normal file
View file

@ -0,0 +1,377 @@
import json
import os
import platform
import shutil
from pathlib import Path
from doit import get_var
from doit.action import CmdAction
ARCH = "arm64" if platform.machine() == "arm64" else "i686"
VERSION = open("share/version.txt").read().strip()
FEDORA_VERSIONS = ["40", "41"]
DEBIAN_VERSIONS = ["bullseye", "focal", "jammy", "mantic", "noble", "trixie"]
# In the case of an Apple Silicon machine, there's no need to run anything else than
# building the .dmg.
if ARCH == "arm64":
DOIT_CONFIG = {'default_tasks': ['macos_build_dmg']}
### Task Parameters
PARAM_APPLE_ID = {
"name": "apple_id",
"long": "apple-id",
"default": "fpf@example.com",
"help": "The Apple developer ID that will be used for signing the .dmg",
}
PARAM_USE_CACHE = {
"name": "use_cache",
"long": "use-cache",
"help": (
"Whether to use cached results or not. For reproducibility reasons,"
" it's best to leave it to false"
),
"default": False,
}
### Global parameters
#
# Read more about global parameters in
# https://pydoit.org/task-args.html#command-line-variables-doit-get-var
CONTAINER_RUNTIME = get_var('runtime', 'podman')
RELEASE_DIR = Path(get_var("release_dir", Path.home() / "release-assets" / VERSION))
### File dependencies
#
# Define all the file dependencies we'll see later in tasks here, since some file
# dependencies are shared between tasks.
def list_files(path, recursive=False):
"""List files in a directory, and optionally traverse into subdirectories."""
filepaths = []
for root, _, files in os.walk(path):
for f in files:
if f.endswith(".pyc"):
continue
filepaths.append(Path(root) / f)
if not recursive:
break
return filepaths
def list_language_data():
"""List the expected language data that Dangerzone downloads and stores locally."""
tessdata_dir = Path("share") / "tessdata"
langs = json.loads(open(tessdata_dir.parent / "ocr-languages.json").read()).values()
targets = [tessdata_dir / f"{lang}.traineddata" for lang in langs]
targets.append(tessdata_dir)
return targets
TESSDATA_DEPS = ["install/common/download-tessdata.py", "share/ocr-languages.json"]
TESSDATA_TARGETS = list_language_data()
IMAGE_DEPS = [
"Dockerfile",
"poetry.lock",
*list_files("dangerzone/conversion"),
"dangerzone/gvisor_wrapper/entrypoint.py",
"install/common/build-image.py",
]
IMAGE_TARGETS = ["share/container.tar.gz", "share/image-id.txt"]
SOURCE_DEPS = [
*list_files("assets"),
*list_files("share"),
*list_files("dangerzone", recursive=True),
]
PYTHON_DEPS = ["poetry.lock", "pyproject.toml"]
DMG_DEPS = [
*list_files("install/macos"),
*TESSDATA_TARGETS,
*IMAGE_TARGETS,
*PYTHON_DEPS,
*SOURCE_DEPS,
]
LINUX_DEPS = [
*list_files("install/linux"),
*IMAGE_TARGETS,
*PYTHON_DEPS,
*SOURCE_DEPS,
]
DEB_DEPS = [*LINUX_DEPS, *list_files("debian")]
RPM_DEPS = [*LINUX_DEPS, *list_files("qubes")]
def copy_dir(src, dst):
"""Copy a directory to a destination dir, and overwrite it if it exists."""
shutil.rmtree(dst, ignore_errors=True)
shutil.copytree(src, dst)
def create_release_dir():
RELEASE_DIR.mkdir(parents=True, exist_ok=True)
(RELEASE_DIR / "assets").mkdir(exist_ok=True)
(RELEASE_DIR / "tmp").mkdir(exist_ok=True)
def build_linux_pkg(distro, version, cwd, qubes=False):
"""Generic command for building a .deb/.rpm in a Dangerzone dev environment."""
pkg = "rpm" if distro == "fedora" else "deb"
cmd = [
"python3",
"./dev_scripts/env.py",
"--distro",
distro,
"--version",
version,
"run",
"--no-gui",
"--dev",
f"./dangerzone/install/linux/build-{pkg}.py",
]
if qubes:
cmd += ["--qubes"]
return CmdAction(" ".join(cmd), cwd=cwd)
def build_deb(cwd):
"""Build a .deb package on Debian Bookworm."""
return build_linux_pkg(distro="debian", version="bookworm", cwd=cwd)
def build_rpm(version, cwd, qubes=False):
"""Build an .rpm package on the requested Fedora distro."""
return build_linux_pkg(distro="Fedora", version=version, cwd=cwd, qubes=qubes)
def task_clean_container_runtime():
"""Clean the storage space of the container runtime."""
return {
"actions": None,
"clean": [
[CONTAINER_RUNTIME, "system", "prune", "-a", "-f"],
],
}
def task_check_container_runtime():
"""Test that the container runtime is ready."""
return {
"actions": [
["which", CONTAINER_RUNTIME],
[CONTAINER_RUNTIME, "ps"],
],
}
def task_macos_check_cert():
"""Test that the Apple developer certificate can be used."""
return {
"actions": [
"xcrun notarytool history --apple-id %(apple_id)s --keychain-profile dz-notarytool-release-key"
],
"params": [PARAM_APPLE_ID],
}
def task_macos_check_system():
"""Run macOS specific system checks, as well as the generic ones."""
return {
"actions": None,
"task_dep": [
"check_container_runtime",
"macos_check_cert",
],
}
def task_init_release_dir():
"""Create a directory for release artifacts."""
return {
"actions": [create_release_dir],
"clean": [f"rm -rf {RELEASE_DIR}"],
}
def task_download_tessdata():
"""Download the Tesseract data using ./install/common/download-tessdata.py"""
return {
"actions": ["python install/common/download-tessdata.py"],
"file_dep": TESSDATA_DEPS,
"targets": TESSDATA_TARGETS,
"clean": True,
}
def task_build_image():
"""Build the container image using ./install/common/build-image.py"""
img_src = "share/container.tar.gz"
img_dst = RELEASE_DIR / f"container-{VERSION}-{ARCH}.tar.gz" # FIXME: Add arch
img_id_src = "share/image-id.txt"
img_id_dst = RELEASE_DIR / "image-id.txt" # FIXME: Add arch
return {
"actions": [
f"python install/common/build-image.py --use-cache=%(use_cache)s --runtime={CONTAINER_RUNTIME}",
f"cp {img_src} {img_dst}",
f"cp {img_id_src} {img_id_dst}",
],
"params": [PARAM_USE_CACHE],
"file_dep": IMAGE_DEPS,
"targets": [img_src, img_dst, img_id_src, img_id_dst],
"task_dep": [
"init_release_dir",
"check_container_runtime",
],
"clean": True,
}
def task_poetry_install():
"""Setup the Poetry environment"""
return {
"actions": ["poetry install --sync"],
}
def task_macos_build_dmg():
"""Build the macOS app bundle for Dangerzone."""
dz_dir = RELEASE_DIR / "tmp" / "macos"
dmg_src = dz_dir / "dist" / "Dangerzone.dmg"
dmg_dst = RELEASE_DIR / f"Dangerzone-{VERSION}-{ARCH}.dmg" # FIXME: Add -arch
return {
"actions": [
(copy_dir, [".", dz_dir]),
f"cd {dz_dir} && poetry run install/macos/build-app.py --with-codesign",
(
"xcrun notarytool submit --wait --apple-id %(apple_id)s"
f" --keychain-profile dz-notarytool-release-key {dmg_src}"
),
f"xcrun stapler staple {dmg_src}",
["cp", "-r", dmg_src, dmg_dst],
["rm", "-rf", dz_dir],
],
"params": [PARAM_APPLE_ID],
"file_dep": DMG_DEPS,
"task_dep": [
"init_release_dir",
"poetry_install",
"download_tessdata",
],
"targets": [dmg_dst],
"clean": True,
}
def task_debian_env():
"""Build a Debian Bookworm dev environment."""
return {
"actions": [
[
"python3",
"./dev_scripts/env.py",
"--distro",
"debian",
"--version",
"bookworm",
"build-dev",
]
],
"task_dep": ["check_container_runtime"],
}
def task_debian_deb():
"""Build a Debian package for Debian Bookworm."""
dz_dir = RELEASE_DIR / "tmp" / "debian"
deb_name = f"dangerzone_{VERSION}-1_amd64.deb"
deb_src = dz_dir / "deb_dist" / deb_name
deb_dst = RELEASE_DIR / deb_name
return {
"actions": [
(copy_dir, [".", dz_dir]),
build_deb(cwd=dz_dir),
["cp", deb_src, deb_dst],
["rm", "-rf", dz_dir],
],
"file_dep": DEB_DEPS,
"task_dep": [
"init_release_dir",
"debian_env",
],
"targets": [deb_dst],
"clean": True,
}
def task_fedora_env():
"""Build Fedora dev environments."""
for version in FEDORA_VERSIONS:
yield {
"name": version,
"actions": [
[
"python3",
"./dev_scripts/env.py",
"--distro",
"fedora",
"--version",
version,
"build-dev",
],
],
"task_dep": ["check_container_runtime"],
}
def task_fedora_rpm():
"""Build Fedora packages for every supported version."""
for version in FEDORA_VERSIONS:
for qubes in (True, False):
qubes_ident = "-qubes" if qubes else ""
dz_dir = RELEASE_DIR / "tmp" / f"f{version}{qubes_ident}"
rpm_names = [
f"dangerzone{qubes_ident}-{VERSION}-1.fc{version}.x86_64.rpm",
f"dangerzone{qubes_ident}-{VERSION}-1.fc{version}.src.rpm",
]
rpm_src = [dz_dir / "dist" / rpm_name for rpm_name in rpm_names]
rpm_dst = [RELEASE_DIR / rpm_name for rpm_name in rpm_names]
yield {
"name": version + qubes_ident,
"actions": [
(copy_dir, [".", dz_dir]),
build_rpm(version, cwd=dz_dir, qubes=qubes),
["cp", *rpm_src, RELEASE_DIR],
["rm", "-rf", dz_dir],
],
"file_dep": RPM_DEPS,
"task_dep": [
"init_release_dir",
f"fedora_env:{version}",
],
"targets": rpm_dst,
"clean": True,
}
def task_git_archive():
"""Build a Git archive of the repo."""
target = f"{RELEASE_DIR}/dangerzone-{VERSION}.tar.gz"
return {
"actions": [
f"git archive --format=tar.gz -o {target} --prefix=dangerzone/ v{VERSION}"
],
"targets": [target],
"task_dep": ["init_release_dir"],
}

View file

@ -2,12 +2,13 @@ import argparse
import gzip import gzip
import os import os
import platform import platform
import secrets
import subprocess import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
BUILD_CONTEXT = "dangerzone/" BUILD_CONTEXT = "dangerzone/"
TAG = "dangerzone.rocks/dangerzone:latest" IMAGE_NAME = "dangerzone.rocks/dangerzone"
REQUIREMENTS_TXT = "container-pip-requirements.txt" REQUIREMENTS_TXT = "container-pip-requirements.txt"
if platform.system() in ["Darwin", "Windows"]: if platform.system() in ["Darwin", "Windows"]:
CONTAINER_RUNTIME = "docker" CONTAINER_RUNTIME = "docker"
@ -16,6 +17,16 @@ elif platform.system() == "Linux":
ARCH = platform.machine() ARCH = platform.machine()
def str2bool(v):
if isinstance(v, bool):
return v
if v.lower() in ('yes', 'true', 't', 'y', '1'):
return True
elif v.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else:
raise argparse.ArgumentTypeError('Boolean value expected.')
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -39,13 +50,39 @@ def main():
) )
parser.add_argument( parser.add_argument(
"--use-cache", "--use-cache",
action="store_true", type=str2bool,
nargs='?',
default=False,
const=True,
help="Use the builder's cache to speed up the builds (not suitable for release builds)", help="Use the builder's cache to speed up the builds (not suitable for release builds)",
) )
args = parser.parse_args() args = parser.parse_args()
tarball_path = Path("share") / "container.tar.gz"
image_id_path = Path("share") / "image-id.txt"
print(f"Building for architecture '{ARCH}'") print(f"Building for architecture '{ARCH}'")
# Designate a unique tag for this image, depending on the Git commit it was created
# from:
# 1. If created from a Git tag (e.g., 0.8.0), the image tag will be `0.8.0`.
# 2. If created from a commit, it will be something like `0.8.0-31-g6bdaa7a`.
# 3. If the contents of the Git repo are dirty, we will append a unique identifier
# for this run, something like `0.8.0-31-g6bdaa7a-fdcb` or `0.8.0-fdcb`.
dirty_ident = secrets.token_hex(2)
tag = (
subprocess.check_output(
["git", "describe", "--first-parent", f"--dirty=-{dirty_ident}"],
)
.decode()
.strip()[1:] # remove the "v" prefix of the tag.
)
image_name_tagged = IMAGE_NAME + ":" + tag
print(f"Will tag the container image as '{image_name_tagged}'")
with open(image_id_path, "w") as f:
f.write(tag)
print("Exporting container pip dependencies") print("Exporting container pip dependencies")
with ContainerPipDependencies(): with ContainerPipDependencies():
if not args.use_cache: if not args.use_cache:
@ -59,8 +96,11 @@ def main():
check=True, check=True,
) )
# Build the container image, and tag it with two tags; the one we calculated
# above, and the "latest" tag.
print("Building container image") print("Building container image")
cache_args = [] if args.use_cache else ["--no-cache"] cache_args = [] if args.use_cache else ["--no-cache"]
image_name_latest = IMAGE_NAME + ":latest"
subprocess.run( subprocess.run(
[ [
args.runtime, args.runtime,
@ -74,7 +114,9 @@ def main():
"-f", "-f",
"Dockerfile", "Dockerfile",
"--tag", "--tag",
TAG, image_name_latest,
"--tag",
image_name_tagged,
], ],
check=True, check=True,
) )
@ -85,7 +127,7 @@ def main():
[ [
CONTAINER_RUNTIME, CONTAINER_RUNTIME,
"save", "save",
TAG, image_name_tagged,
], ],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
) )
@ -93,7 +135,7 @@ def main():
print("Compressing container image") print("Compressing container image")
chunk_size = 4 << 20 chunk_size = 4 << 20
with gzip.open( with gzip.open(
"share/container.tar.gz", tarball_path,
"wb", "wb",
compresslevel=args.compress_level, compresslevel=args.compress_level,
) as gzip_f: ) as gzip_f:
@ -105,21 +147,6 @@ def main():
break break
cmd.wait(5) cmd.wait(5)
print("Looking up the image id")
image_id = subprocess.check_output(
[
args.runtime,
"image",
"list",
"--format",
"{{.ID}}",
TAG,
],
text=True,
)
with open("share/image-id.txt", "w") as f:
f.write(image_id)
class ContainerPipDependencies: class ContainerPipDependencies:
"""Generates PIP dependencies within container""" """Generates PIP dependencies within container"""

39
poetry.lock generated
View file

@ -229,6 +229,17 @@ files = [
[package.dependencies] [package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""} colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "cloudpickle"
version = "3.1.0"
description = "Pickler class to extend the standard pickle.Pickler functionality"
optional = false
python-versions = ">=3.8"
files = [
{file = "cloudpickle-3.1.0-py3-none-any.whl", hash = "sha256:fe11acda67f61aaaec473e3afe030feb131d78a43461b718185363384f1ba12e"},
{file = "cloudpickle-3.1.0.tar.gz", hash = "sha256:81a929b6e3c7335c863c771d673d105f02efdb89dfaba0c90495d1c64796601b"},
]
[[package]] [[package]]
name = "colorama" name = "colorama"
version = "0.4.6" version = "0.4.6"
@ -412,6 +423,24 @@ files = [
{file = "cx_logging-3.2.1.tar.gz", hash = "sha256:812665ae5012680a6fe47095c3772bce638e47cf05b2c3483db3bdbe6b06da44"}, {file = "cx_logging-3.2.1.tar.gz", hash = "sha256:812665ae5012680a6fe47095c3772bce638e47cf05b2c3483db3bdbe6b06da44"},
] ]
[[package]]
name = "doit"
version = "0.36.0"
description = "doit - Automation Tool"
optional = false
python-versions = ">=3.8"
files = [
{file = "doit-0.36.0-py3-none-any.whl", hash = "sha256:ebc285f6666871b5300091c26eafdff3de968a6bd60ea35dd1e3fc6f2e32479a"},
{file = "doit-0.36.0.tar.gz", hash = "sha256:71d07ccc9514cb22fe59d98999577665eaab57e16f644d04336ae0b4bae234bc"},
]
[package.dependencies]
cloudpickle = "*"
importlib-metadata = ">=4.4"
[package.extras]
toml = ["tomli"]
[[package]] [[package]]
name = "exceptiongroup" name = "exceptiongroup"
version = "1.2.2" version = "1.2.2"
@ -554,7 +583,6 @@ python-versions = ">=3.8"
files = [ files = [
{file = "lief-0.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a80246b96501b2b1d4927ceb3cb817eda9333ffa9e07101358929a6cffca5dae"}, {file = "lief-0.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a80246b96501b2b1d4927ceb3cb817eda9333ffa9e07101358929a6cffca5dae"},
{file = "lief-0.15.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:84bf310710369544e2bb82f83d7fdab5b5ac422651184fde8bf9e35f14439691"}, {file = "lief-0.15.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:84bf310710369544e2bb82f83d7fdab5b5ac422651184fde8bf9e35f14439691"},
{file = "lief-0.15.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:517dc5dad31c754720a80a87ad9e6cb1e48223d4505980c2fd86072bd4f69001"},
{file = "lief-0.15.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:8fb58efb77358291109d2675d5459399c0794475b497992d0ecee18a4a46a207"}, {file = "lief-0.15.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:8fb58efb77358291109d2675d5459399c0794475b497992d0ecee18a4a46a207"},
{file = "lief-0.15.1-cp310-cp310-manylinux_2_33_aarch64.whl", hash = "sha256:d5852a246361bbefa4c1d5930741765a2337638d65cfe30de1b7d61f9a54b865"}, {file = "lief-0.15.1-cp310-cp310-manylinux_2_33_aarch64.whl", hash = "sha256:d5852a246361bbefa4c1d5930741765a2337638d65cfe30de1b7d61f9a54b865"},
{file = "lief-0.15.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:12e53dc0253c303df386ae45487a2f0078026602b36d0e09e838ae1d4dbef958"}, {file = "lief-0.15.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:12e53dc0253c303df386ae45487a2f0078026602b36d0e09e838ae1d4dbef958"},
@ -562,7 +590,6 @@ files = [
{file = "lief-0.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ddf2ebd73766169594d631b35f84c49ef42871de552ad49f36002c60164d0aca"}, {file = "lief-0.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ddf2ebd73766169594d631b35f84c49ef42871de552ad49f36002c60164d0aca"},
{file = "lief-0.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20508c52de0dffcee3242253541609590167a3e56150cbacb506fdbb822206ef"}, {file = "lief-0.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20508c52de0dffcee3242253541609590167a3e56150cbacb506fdbb822206ef"},
{file = "lief-0.15.1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:0750c892fd3b7161a3c2279f25fe1844427610c3a5a4ae23f65674ced6f93ea5"}, {file = "lief-0.15.1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:0750c892fd3b7161a3c2279f25fe1844427610c3a5a4ae23f65674ced6f93ea5"},
{file = "lief-0.15.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:3e49bd595a8548683bead982bc15b064257fea3110fd15e22fb3feb17d97ad1c"},
{file = "lief-0.15.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a8634ea79d6d9862297fadce025519ab25ff01fcadb333cf42967c6295f0d057"}, {file = "lief-0.15.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a8634ea79d6d9862297fadce025519ab25ff01fcadb333cf42967c6295f0d057"},
{file = "lief-0.15.1-cp311-cp311-manylinux_2_33_aarch64.whl", hash = "sha256:1e11e046ad71fe8c81e1a8d1d207fe2b99c967d33ce79c3d3915cb8f5ecacf52"}, {file = "lief-0.15.1-cp311-cp311-manylinux_2_33_aarch64.whl", hash = "sha256:1e11e046ad71fe8c81e1a8d1d207fe2b99c967d33ce79c3d3915cb8f5ecacf52"},
{file = "lief-0.15.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:674b620cdf1d686f52450fd97c1056d4c92e55af8217ce85a1b2efaf5b32140b"}, {file = "lief-0.15.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:674b620cdf1d686f52450fd97c1056d4c92e55af8217ce85a1b2efaf5b32140b"},
@ -570,15 +597,11 @@ files = [
{file = "lief-0.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:e9b96a37bf11ca777ff305d85d957eabad2a92a6e577b6e2fb3ab79514e5a12e"}, {file = "lief-0.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:e9b96a37bf11ca777ff305d85d957eabad2a92a6e577b6e2fb3ab79514e5a12e"},
{file = "lief-0.15.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1a96f17c2085ef38d12ad81427ae8a5d6ad76f0bc62a1e1f5fe384255cd2cc94"}, {file = "lief-0.15.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1a96f17c2085ef38d12ad81427ae8a5d6ad76f0bc62a1e1f5fe384255cd2cc94"},
{file = "lief-0.15.1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:d780af1762022b8e01b613253af490afea3864fbd6b5a49c6de7cea8fde0443d"}, {file = "lief-0.15.1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:d780af1762022b8e01b613253af490afea3864fbd6b5a49c6de7cea8fde0443d"},
{file = "lief-0.15.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:536a4ecd46b295b3acac0d60a68d1646480b7761ade862c6c87ccbb41229fae3"},
{file = "lief-0.15.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d0f10d80202de9634a16786b53ba3a8f54ae8b9a9e124a964d83212444486087"}, {file = "lief-0.15.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d0f10d80202de9634a16786b53ba3a8f54ae8b9a9e124a964d83212444486087"},
{file = "lief-0.15.1-cp312-cp312-manylinux_2_33_aarch64.whl", hash = "sha256:864f17ecf1736296e6d5fc38b11983f9d19a5e799f094e21e20d58bfb1b95b80"}, {file = "lief-0.15.1-cp312-cp312-manylinux_2_33_aarch64.whl", hash = "sha256:864f17ecf1736296e6d5fc38b11983f9d19a5e799f094e21e20d58bfb1b95b80"},
{file = "lief-0.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c2ec738bcafee8a569741f4a749f0596823b12f10713306c7d0cbbf85759f51c"}, {file = "lief-0.15.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c2ec738bcafee8a569741f4a749f0596823b12f10713306c7d0cbbf85759f51c"},
{file = "lief-0.15.1-cp312-cp312-win32.whl", hash = "sha256:db38619edf70e27fb3686b8c0f0bec63ad494ac88ab51660c5ecd2720b506e41"}, {file = "lief-0.15.1-cp312-cp312-win32.whl", hash = "sha256:db38619edf70e27fb3686b8c0f0bec63ad494ac88ab51660c5ecd2720b506e41"},
{file = "lief-0.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:28bf0922de5fb74502a29cc47930d3a052df58dc23ab6519fa590e564f194a60"}, {file = "lief-0.15.1-cp312-cp312-win_amd64.whl", hash = "sha256:28bf0922de5fb74502a29cc47930d3a052df58dc23ab6519fa590e564f194a60"},
{file = "lief-0.15.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0805301e8fef9b13da00c33c831fb0c05ea892309230f3a35551c2dfaf69b11d"},
{file = "lief-0.15.1-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:7580defe140e921bc4f210e8a6cb115fcf2923f00d37800b1626168cbca95108"},
{file = "lief-0.15.1-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:c0119306b6a38759483136de7242b7c2e0a23f1de1d4ae53f12792c279607410"},
{file = "lief-0.15.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0616e6048f269d262ff93d67c497ebff3c1d3965ffb9427b0f2b474764fd2e8c"}, {file = "lief-0.15.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0616e6048f269d262ff93d67c497ebff3c1d3965ffb9427b0f2b474764fd2e8c"},
{file = "lief-0.15.1-cp313-cp313-manylinux_2_33_aarch64.whl", hash = "sha256:6a08b2e512a80040429febddc777768c949bcd53f6f580e902e41ec0d9d936b8"}, {file = "lief-0.15.1-cp313-cp313-manylinux_2_33_aarch64.whl", hash = "sha256:6a08b2e512a80040429febddc777768c949bcd53f6f580e902e41ec0d9d936b8"},
{file = "lief-0.15.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fcd489ff80860bcc2b2689faa330a46b6d66f0ee3e0f6ef9e643e2b996128a06"}, {file = "lief-0.15.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fcd489ff80860bcc2b2689faa330a46b6d66f0ee3e0f6ef9e643e2b996128a06"},
@ -586,7 +609,6 @@ files = [
{file = "lief-0.15.1-cp313-cp313-win_amd64.whl", hash = "sha256:5af7dcb9c3f44baaf60875df6ba9af6777db94776cc577ee86143bcce105ba2f"}, {file = "lief-0.15.1-cp313-cp313-win_amd64.whl", hash = "sha256:5af7dcb9c3f44baaf60875df6ba9af6777db94776cc577ee86143bcce105ba2f"},
{file = "lief-0.15.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9757ff0c7c3d6f66e5fdcc6a9df69680fad0dc2707d64a3428f0825dfce1a85"}, {file = "lief-0.15.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9757ff0c7c3d6f66e5fdcc6a9df69680fad0dc2707d64a3428f0825dfce1a85"},
{file = "lief-0.15.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:8ac3cd099be2580d0e15150b1d2f5095c38f150af89993ddf390d7897ee8135f"}, {file = "lief-0.15.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:8ac3cd099be2580d0e15150b1d2f5095c38f150af89993ddf390d7897ee8135f"},
{file = "lief-0.15.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e732619acc34943b504c867258fc0196f1931f72c2a627219d4f116a7acc726d"},
{file = "lief-0.15.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4dedeab498c312a29b58f16b739895f65fa54b2a21b8d98b111e99ad3f7e30a8"}, {file = "lief-0.15.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4dedeab498c312a29b58f16b739895f65fa54b2a21b8d98b111e99ad3f7e30a8"},
{file = "lief-0.15.1-cp38-cp38-manylinux_2_33_aarch64.whl", hash = "sha256:b9217578f7a45f667503b271da8481207fb4edda8d4a53e869fb922df6030484"}, {file = "lief-0.15.1-cp38-cp38-manylinux_2_33_aarch64.whl", hash = "sha256:b9217578f7a45f667503b271da8481207fb4edda8d4a53e869fb922df6030484"},
{file = "lief-0.15.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:82e6308ad8bd4bc7eadee3502ede13a5bb398725f25513a0396c8dba850f58a1"}, {file = "lief-0.15.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:82e6308ad8bd4bc7eadee3502ede13a5bb398725f25513a0396c8dba850f58a1"},
@ -594,7 +616,6 @@ files = [
{file = "lief-0.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:a079a76bca23aa73c850ab5beb7598871a1bf44662658b952cead2b5ddd31bee"}, {file = "lief-0.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:a079a76bca23aa73c850ab5beb7598871a1bf44662658b952cead2b5ddd31bee"},
{file = "lief-0.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:785a3aa14575f046ed9c8d44ea222ea14c697cd03b5331d1717b5b0cf4f72466"}, {file = "lief-0.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:785a3aa14575f046ed9c8d44ea222ea14c697cd03b5331d1717b5b0cf4f72466"},
{file = "lief-0.15.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:d7044553cf07c8a2ab6e21874f07585610d996ff911b9af71dc6085a89f59daa"}, {file = "lief-0.15.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:d7044553cf07c8a2ab6e21874f07585610d996ff911b9af71dc6085a89f59daa"},
{file = "lief-0.15.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:fa020f3ed6e95bb110a4316af544021b74027d18bf4671339d4cffec27aa5884"},
{file = "lief-0.15.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:13285c3ff5ef6de2421d85684c954905af909db0ad3472e33c475e5f0f657dcf"}, {file = "lief-0.15.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:13285c3ff5ef6de2421d85684c954905af909db0ad3472e33c475e5f0f657dcf"},
{file = "lief-0.15.1-cp39-cp39-manylinux_2_33_aarch64.whl", hash = "sha256:932f880ee8a130d663a97a9099516d8570b1b303af7816e70a02f9931d5ef4c2"}, {file = "lief-0.15.1-cp39-cp39-manylinux_2_33_aarch64.whl", hash = "sha256:932f880ee8a130d663a97a9099516d8570b1b303af7816e70a02f9931d5ef4c2"},
{file = "lief-0.15.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:de9453f94866e0f2c36b6bd878625880080e7e5800788f5cbc06a76debf283b9"}, {file = "lief-0.15.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:de9453f94866e0f2c36b6bd878625880080e7e5800788f5cbc06a76debf283b9"},
@ -1189,4 +1210,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 = "5d1ff28aa04c3a814280e55c0b2a307efe5ca953cd4cb281056c35fd2e53fdf0" content-hash = "8367cee9a978ba6df32f44e902d223156e321b2cb4ea8a9d7a4bf1f88392a8c0"

View file

@ -23,6 +23,7 @@ pyxdg = {version = "*", platform = "linux"}
requests = "*" requests = "*"
markdown = "*" markdown = "*"
packaging = "*" packaging = "*"
doit = "^0.36.0"
[tool.poetry.scripts] [tool.poetry.scripts]
dangerzone = 'dangerzone:main' dangerzone = 'dangerzone:main'
@ -66,6 +67,26 @@ skip_gitignore = true
# This is necessary due to https://github.com/PyCQA/isort/issues/1835 # This is necessary due to https://github.com/PyCQA/isort/issues/1835
follow_links = false follow_links = false
[tool.doit.commands.clean]
# XXX: Change this to false if you REALLY want to clean your environment. Note
# that this command will:
# * prune container images,
# * clean the Git repo, and
# * remove all tasks output
#
# Else, the `doit clean` comamnd will print the commands that would run instead.
dryrun = true
[tool.doit.tasks.macos_check_cert]
apple_id = "fpf@example.com"
[tool.doit.tasks.macos_codesign]
apple_id = "fpf@example.com"
[tool.doit.tasks.build_image]
use_cache = false
force_tag = ""
[build-system] [build-system]
requires = ["poetry-core>=1.2.0"] requires = ["poetry-core>=1.2.0"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"

View file

@ -30,6 +30,7 @@ from dangerzone.isolation_provider.container import (
NoContainerTechException, NoContainerTechException,
NotAvailableContainerTechException, NotAvailableContainerTechException,
) )
from dangerzone.isolation_provider.dummy import Dummy
from .test_updater import assert_report_equal, default_updater_settings from .test_updater import assert_report_equal, default_updater_settings
@ -510,9 +511,9 @@ def test_not_available_container_tech_exception(
) -> None: ) -> None:
# Setup # Setup
mock_app = mocker.MagicMock() mock_app = mocker.MagicMock()
dummy = mocker.MagicMock() dummy = Dummy()
fn = mocker.patch.object(dummy, "is_runtime_available")
dummy.is_runtime_available.side_effect = NotAvailableContainerTechException( fn.side_effect = NotAvailableContainerTechException(
"podman", "podman image ls logs" "podman", "podman image ls logs"
) )

View file

@ -69,10 +69,11 @@ class TestContainer(IsolationProviderTest):
"image", "image",
"list", "list",
"--format", "--format",
"{{.ID}}", "json",
"dangerzone.rocks/dangerzone", "dangerzone.rocks/dangerzone",
], ],
occurrences=2, occurrences=2,
stdout="{}",
) )
# Make podman load fail # Make podman load fail
@ -102,10 +103,11 @@ class TestContainer(IsolationProviderTest):
"image", "image",
"list", "list",
"--format", "--format",
"{{.ID}}", "json",
"dangerzone.rocks/dangerzone", "dangerzone.rocks/dangerzone",
], ],
occurrences=2, occurrences=2,
stdout="{}",
) )
# Patch gzip.open and podman load so that it works # Patch gzip.open and podman load so that it works