SecureDrop Client Development

As part of the ongoing work to make an integrated journalist-friendly workstation for SecureDrop we have created a native client application to be run within the Qubes operating system. It helps journalists with the most common activities associated with using SecureDrop in a user friendly manner.

Currently the client is alpha quality although work is ongoing in terms of improving features and the user interface.

The source code, and related issues are hosted on GitHub.

Developer Setup

You may find developer setup instructions in the SecureDrop Client README.

How to Find Help

If you would like to report a problem submit a new issue.

If you’d like to chat with other developers working on the client drop into our Gitter chat channel for the project.

Every non-public holiday weekday (except Fridays) at 10am (Pacific Time) we take part in a public daily stand-up, usually via a meeting on Google Meet. Connection information for standups is published periodically on the Gitter channel. All are welcome to contribute.

Otherwise, read on.

Client Architecture

The SecureDrop client is a PyQt application. It’s written using Python 3.11 and the Python bindings for the Qt UI framework (PyQt).

In the root directory of the repository are two important directories: securedrop_client (containing the application code) and tests containing our unit tests. You’ll also find a Makefile in the root directory which defines commands to run commonly needed activities. Type, make to find out what commands are available.

The code in the securedrop_client namespace is organised in the following way:

  • - starts and configures the application.

  • - contains the application logic, encapsulated in the Client class.

  • - holds all the SQLAlchemy ORM model definitions for interacting with the local Sqlite database.

  • - contains the functions needed for interacting with a remote SecureDrop API and the local database.

  • - generic utility functions needed throughout the application.

  • gui - this namespace contains two modules: (containing the Window class through which all interactions with the user interface should happen) and (containing all the custom widgets used by the Window class to draw the user interface).

We try very hard to keep the application logic and UI code cleanly separated. Furthermore, we try equally hard to ensure the main GUI code always remains unblocked. For instance look at how the APICallRunner is used in to make unblocked network calls to the remote API.

We encourage developers to make sure all classes, methods and functions have docstrings describing the intention behind the code. Obviously, it’s important that such docstrings remain up to date as the code evolves.

We make use of ruff, mypy, and other linting tools to standardize code style. Please run make lint locally from both the project root and the client directories before submitting a PR.

Client Database Structure

For a better understanding of the SecureDrop Client application architecture, a high-level view of its database structure has been provided:



The files and directory structure found within the tests directory mirrors that of the files and directories in securedrop_client. For instance, all the unit tests for the securedrop_client/ module can be found in the tests/ file.

To run the complete test suite simply type:

make check

Our code style checkers, full test suite and coverage checker will run and report any errors.

We use the PyTest testing framework for writing and running our unit tests. We expect every test to have an associated comment which describes the intent of the test. As far as possible, tests should be self contained with all the context needed to understand them within each individual unit test (this makes it easier to debug things when the test suite fails as the codebase evolves).

Take a look in any of the test files to see the sort of code we expect for unit tests.

We currently have, and expect to maintain, 100% unit test coverage of our code base. If you’re unsure how to achieve this, please don’t hesitate to get in touch via Gitter or mention this in your description of any pull requests you submit.


Our open issues are on GitHub.

Please remember that we have a Code of Conduct and expect all contributors to abide by it.

Before submitting a pull request, make sure the test suite passes (make check), because our CI tools will flag broken tests before we’re able to merge your code into main.

Most of all, please don’t hesitate to get in touch if you need help, advice or would like guidance.

Thank you for your support!