Automated updates for stand-alone Python applications, built upon python-tuf.
Project description
tufup
A simple software updater for stand-alone Python applications.
The tufup package is built on top of python-tuf, which is the reference implementation for TUF (The Update Framework).
It is advisable to read the TUF documentation before proceeding.
An application example can be found in the companion repository: tufup-example
About
The tufup package was inspired by PyUpdater, and uses a general approach to updating that is directly based on PyUpdater's implementation.
However, whereas PyUpdater implements a custom security mechanism to ensure authenticity (and integrity) of downloaded update files, tufup is built on top of the security mechanisms implemented in the python-tuf package, a.k.a. tuf.
By entrusting the design of security measures to the security professionals, tufup can focus on high-level tools.
Although tuf supports highly complex security infrastructures, see e.g. PEP458, it also offers sufficient flexibility to allow application developers to tailor the security level to their use case.
For details and best practices, refer to the tuf docs.
Based on the intended use, the tufup package supports only the top-level roles offered by tuf. At this time we do not support delegations.
Overview
Borrowing TUF terminology, we distinguish between a repo-side (repository) and a client-side (application).
Below you'll find a list of the basic steps that occur in an application update cycle.
Steps covered by tufup are highlighted.
On the repo-side, the app developer
- modifies the application code
- creates a new application archive file and corresponding patch file
- signs the resulting files cryptographically
- deploys these files to a server
On the client-side, the application
- checks for updates
- downloads update files
- applies the update files (i.e. installation)
The tuf package is used under the hood to check for updates and download update files in a secure manner, so tufup can safely apply the update.
See the tuf docs for more information.
Archives and patches
Tufup works with archives (e.g. gzipped PyInstaller bundles) and patches (binary differences between subsequent archives). Each archive, except the first one, must have a corresponding patch file.
Archive filenames and patch filenames follow the pattern
<name>-<version><suffix>
where name is a short string that may contain alphanumeric characters, underscores, and hyphens, version is a version string according to the PEP440 specification, and suffix is either '.tar.gz' or '.patch'.
Patches are typically smaller than archives, so the tufup client will always attempt to update using one or more patches. However, if the total amount of patch data is greater than the desired full archive file, a full update will be performed.
How updates are created (repo-side)
When a new release of your application is ready, the following steps need to be taken to enable clients to update to that new release:
- Create an application archive for the new release (e.g. a zipped PyInstaller bundle).
- Create a patch from the current archive to the new archive.
- Add hashes for the newly created archive file and patch file to the
tufmetadata. - Sign the modified
tufmetadata files. - Upload the new target files, i.e. archive and patch, and the updated metadata files, to the update server.
The signed metadata and hashes ensure both authenticity and integrity of the update files (see tuf docs).
In order to sign the metadata, we need access to the private key files for the applicable tuf roles.
The tufup.repo module provides a convenient way to streamline the above procedure, based on the tuf basic repo example.
How updates are applied (client-side)
By default, updates are applied by copying all files and folders from the latest archive to the current app installation directory.
Here's what happens during the update process:
- The latest archive is either downloaded in full, as described above, or it is derived from the current archive by applying one or more downloaded patches.
- Once the latest archive is available on disk, it is decompressed to a temporary directory.
- A default install script is then started, which copies the new files and folders from the temporary directory to the current app installation directory. On Windows, this script is started in a new process, after which the currently running process will exit.
- Alternatively, you can specify a custom install script to do whatever you want with the new files.
The default install script accepts an optional purge_dst_dir argument, which will cause ALL files and folders to be deleted from the app installation directory, before moving the new files into place.
This is a convenient way to remove any stale files and folders from the app installation directory.
WARNING: The
purge_dst_diroption should only be used if the app is properly installed in its own separate directory. If this is not the case, for example if the app is running from the WindowsDesktopdirectory, any unrelated files or folders in this directory will also be deleted!
Migrating from other update frameworks
Here's one way to migrate from another update framework, such as pyupdater, to tufup:
- Add
tufupto your main application environment as a core dependency, and movepyupdaterfrom core dependencies to development dependencies. - Replace all
pyupdaterclient code (and configuration) in your application by thetufupclient. - Initialize the
tufuprepository, so the root metadata fileroot.jsonexists. - Modify your PyInstaller
.specfile (from PyUpdater) to ensure that theroot.jsonfile is included in your package. - Build, package, and sign using
pyupdater, and deploy to your server, as usual. This ensures that yourpyupdaterclients currently in the field will be able to update to the newtufupclient. - From here on, new updates will be deployed using
tufup. - If you want to enable a patch update from the
pyupdaterversion to the newtufupversion, extract the latest PyUpdater archive and add the resulting bundle to thetufuprepository. - To skip patch creation, just create a new app bundle and add that to the
tufuprepository. - BEWARE: Keep the
pyupdaterrepository in place as long as necessary to allow all clients to update. - From now on, build, package, sign and deploy using
tufup, as described elsewhere in this document.
Platform support
The tufup.client tools are aimed primarily at Windows and macOS applications, whereas the tufup.repo tools are platform independent, as tufup.repo is just a thin layer on top of python-tuf.
Although tufup.client could also be used for Linux applications, those are probably better off using native packaging solutions, or solutions such as Flatpak or Snapcraft.
Read the Python packaging overview for more information.
Platform dependence for tufup.client is related to file handling and process handling during the installation procedure, as can be seen in tufup.utils.platform_specific.
A custom, platform dependent, installation procedure can be specified via the optional install argument for the Client.update() method.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tufup-0.4.1.tar.gz.
File metadata
- Download URL: tufup-0.4.1.tar.gz
- Upload date:
- Size: 30.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ecff7cdacccc0dd79c3d144633c9b00760c8b473db87b599f46ff2f419699a8d
|
|
| MD5 |
a381945cc991f362de855a98baccfd93
|
|
| BLAKE2b-256 |
04d64d8f6fc1a5434edc2cb6f5ebe2f005f6b64d1d21813d87378ae2d64e3fd0
|
File details
Details for the file tufup-0.4.1-py3-none-any.whl.
File metadata
- Download URL: tufup-0.4.1-py3-none-any.whl
- Upload date:
- Size: 29.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8ebc77a91a5de59934d5e26b9701421ce2799af2b63c90638ba81f426b54d74
|
|
| MD5 |
2685e986b7b04d54b8b1062e5ab023b7
|
|
| BLAKE2b-256 |
513bde14202618f236195b0e1e24cf6a244f3efcba8bec619e2e8dbbf335ecce
|