Skip to content

Provide *-full packages for Linux, and remove container.tar from default ones#1423

Open
almet wants to merge 21 commits intomainfrom
1069-dangerzone-slim-packages
Open

Provide *-full packages for Linux, and remove container.tar from default ones#1423
almet wants to merge 21 commits intomainfrom
1069-dangerzone-slim-packages

Conversation

@almet
Copy link
Copy Markdown
Member

@almet almet commented Feb 11, 2026

This removes the container.tar from the Linux packages, providing -full variants for the versions with the container.

This doesn't currently change how windows and macOS installers are created. Currently they continue shipping with the container.tar inside.

@almet almet changed the title Remove container.tar from dangerzone package Provide *-full packages for Linux, and remove container.tar from default ones Feb 12, 2026
Comment thread dangerzone/gui/updater.py Outdated

MSG_CONFIRM_DOWNLOAD_CONTAINER = """\
<p>
<b>Enable sandbox download?</b>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<b>Enable sandbox download?</b>
<b>Download conversion sandbox?</b>

Comment thread dangerzone/gui/updater.py Outdated
Comment on lines +45 to +48
<p>This is <b>required</b> for Dangerzone to work. If you prefer an offline install,
you can download the full version with an embedded container.</p>

<p>If you need to run Dangerzone in an air-gapped environment, see <a href="https://github.com/freedomofpress/dangerzone/blob/main/docs/developer/independent-container-updates.md#installing-image-updates-to-air-gapped-environments">our documentation</a>.</p>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between an offline install and an airgapped install? Can we merge these somehow?

settings.set("updater_last_check", 0, autosave=True)
# If no container is bundled and none is installed, we must prompt the user
# to enable updates immediately, otherwise Dangerzone won't work.
if not is_container_tar_bundled() and not LAST_LOG_INDEX.exists():
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if last log index exists, but the Podman storage was erased in the meantime?

Comment thread dangerzone/cli.py
+ " Please initialize Dangerzone by running:\n\n"
" dangerzone-image upgrade\n"
)
sys.exit(1)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't offer a way to auto-download the image via the CLI, then this should be recorded as a breaking change, at least for new installations.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, and even more: we'll need to record this as a breaking change in any case, unless we decide it's an opt-out feature.

I was thinking about providing an --upgrade option to the cli, but having dangerzone-image upgrade might be better? Any thoughts?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, no clue if one or the other is more useful. I'd keep them separate for now (so just use dangerzone-image upgrade) and check for user requests.

Comment thread dangerzone/startup.py
return True
except updater_errors.NeedUserInput as e:
download_required = isinstance(e, updater_errors.NeedUserInputNoContainer)
accepted = self.prompt_user(download_required=download_required)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have moved user interactions to the dangerzone/gui/startup.py module, since it's GUI-aware. At least until we have CLI interactions as well.

Comment thread install/linux/build-deb.py Outdated
Comment on lines +51 to +58
control_new = (
control_orig.replace("Source: dangerzone", "Source: dangerzone-full")
.replace("Package: dangerzone", "Package: dangerzone-full")
.replace(
"Conflicts: dangerzone-full, dangerzone-qubes",
"Conflicts: dangerzone, dangerzone-qubes",
)
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there a way to have two control files for separate packages? I haven't dug into it yet, just asking.

almet and others added 21 commits April 20, 2026 12:32
The conversion error classes used to live under dangerzone/conversion/
which is the code that runs inside the container. Now that the
container image lives in a separate repository, the "client" side needs
its own copy of the error types and shared constants (DEFAULT_DPI,
INT_BYTES, MAX_PAGES) so it can decode the integer error codes that
cross the sandbox boundary.

This is now in dangerzone/conversion_errors.py with the ConversionException
hierarchy and the constants that the client needs. Isolation provider tests
have been modified to use this new location.
The container image build, the conversion code that runs inside it,
and the related CI/Dockerfiles now live in the freedomofpress/
dangerzone-image repository. Remove them from this repo and rewire
the build pipeline to consume the published container image instead
of building it in this repo.

This drops the following folders and files: conversion/,
container_helpers/, the Dockerfiles, the in-tree image build scripts, and
updates ci.yml to call `dangerzone-image prepare-archive` against the published
image rather than building it locally.
Now that the container image (and the actual format conversion) lives
in a separate repo, this repo only needs to test the client-side
interface to the sandbox, not the round-trip conversion of every
supported format. Drop the per-format sample documents, their
reference PDFs, the external HWP fixtures, the 11k-page compressed
fixture, and the test_large_set.py module.

Also drop the tests that exercised the now-removed conversion code:
test_max_pages_server_enforcement (this is the container repo's concern) and
the TestExtraFormats CLI test for HWP.
With the format-specific assets gone, the GUI and isolation provider
tests no longer need a non-PDF document to drive their drag-drop and
multi-document scenarios.

Also refresh sample-pdf.pdf and its reference output to the latest
version.
Set QT_QPA_PLATFORM=offscreen in tests/gui/conftest.py so the GUI test
suite renders without a display server. Add an `--onscreen` opt-out
for local debugging.

With offscreen rendering in place, the CI job no longer needs to
install xvfb, start an Xvfb server, or wrap the test command in
xvfb-run. Drop all of that and pass `--no-gui` to dev_scripts/env.py
so it doesn't try to forward the (now nonexistent) host X socket into
the container.
Mark the container-backed tests (tests/isolation_provider/test_container.py
and TestCliConversion in tests/test_cli.py) and the GUI tests as
belonging to dedicated xdist groups so pytest-xdist runs each group
on a single worker. This avoids contention over the container runtime
and the offscreen Qt platform when running tests in parallel.

Also register the xdist_group marker via addinivalue_line so it
doesn't trigger PytestUnknownMarkWarning when pytest-xdist isn't
installed (the marker is then a no-op), and group otherwise-ungrouped
tests by file in tests/conftest.py so they never accidentally land on
the container or gui worker.
The DangerzoneGui.__init__ logic that orders MIME handlers walks
$XDG_DATA_DIRS to find .desktop files. Pin XDG_DATA_DIRS to a known
value in the three GUI logic tests that exercise this path so the
tests don't pick up arbitrary entries from the developer's or CI
runner's environment.
Bump vfkit to 0.6.3 (now signed upstream, so use vfkit-unsigned and
relax the version pin to >=0.6.1) and cosign to 2.6.3 in mazette.lock,
and refresh the mazette config_checksum.

Regenerate poetry.lock with Poetry 2.3, which adds platform/group
markers to a couple of entries.
The conversion code that used to live in this repo now lives in
`dangerzone-image`. Adjust this branch to that split:

- Drop the `tests/test_docs_large` submodule (moved to dangerzone-image).
- Add `dangerzone-insecure-conversion` as a git dependency so the
  `conversion` Python module is available for providers that import it
  directly (notably the Qubes provider, which does
  `import conversion as _conv`).
Add the possibility to generate a `dangerzone-slim` RPM that does not
include the `container.tar` file. Built with:

    ./install/linux/build-rpm.py --slim
Provide a `dangerzone-slim` Debian package alongside the full one. The
slim variant ships without `container.tar`; the container image is
fetched at runtime.

This commit also reshapes the Debian build flow so that `debian/rules`
drives the packaging (via `debian/control`), rather than carrying the
full packaging logic inside `install/linux/build-deb.py`. The Python
script is now a thin driver around `dpkg-buildpackage`.
Teach the `doit` task graph about the slim/full split: separate tasks
for building each flavor, correct dependencies between them, and updated
developer docs (`docs/developer/doit.md`) describing the new tasks.
Make slim the default on Linux: the `dangerzone` package no longer
bundles `container.tar`, and a new `dangerzone-full` package provides
the bundled-image variant for users who want the legacy behavior.

Updates to RPM spec, Debian control, build scripts, installer docs, and
the updater's expected install paths so they all agree on the new
layout.
When the packaged image is absent (slim install), the GUI must:

- Detect that the first-run sandbox download is needed and prompt the
  user for it via the updater flow.
- Surface a clear error state if the download is refused or fails,
  rather than crashing deep in the isolation provider.
- Thread a `NoContainerImageError` through `startup.py` so the main
  window can render a recoverable error.
The CLI, unlike the GUI, cannot prompt the user to download the image.
If no image is available, exit with a clear error message pointing at
`dangerzone-image` rather than failing opaquely during conversion.
On Linux there is no Podman virtual machine to manage, so logging
machine init/start/stop at INFO just clutters the user-visible output.
Drop those messages to DEBUG; keep INFO for Windows and macOS where the
machine is a real moving part.
The apt-tools-prod and yum-tools-prod repos moved to
`github.com/freedomofpress/packages`. Update release/build docs to
point there.
Add a CI job that builds and installs `dangerzone-slim.deb`, fetches
the container image via `dangerzone-image`, and runs a smoke
conversion through `dangerzone-cli`. Also:

- Upload the `-full.deb` artifact only once per run to avoid duplicate
  uploads.
- Download container images before invoking the CLI so the job doesn't
  race the first-run install path.
- Order CI steps so each build step is immediately followed by its
  upload (build → upload → build → upload).
Document the slim/full split and the new `dangerzone-slim` packages in
`CHANGELOG.md`.
Test dangerzone-full on fedora. Extend the build-install-rpm job to also
build the dangerzone-full .rpm (via `build-rpm.py --full`) and upload it
as a separate artifact.

Clarify in docs/developer/release/build.md that build-deb.py produces
both the slim and -full .deb in a single run, and that both .rpms must
be published to the packages repo.
@almet almet force-pushed the 1069-dangerzone-slim-packages branch from 93a1e93 to b4a9169 Compare April 22, 2026 15:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants