The Update Framework (TUF) for Python

6.0.0 · active · verified Thu Apr 16

python-tuf is the Python reference implementation of The Update Framework (TUF), a framework for securing software update systems against various supply chain attacks. It provides APIs for both client-side artifact verification (`tuf.ngclient`) and repository-side metadata management (`tuf.api.metadata`). The library is actively maintained and currently at version 6.0.0, with a release cadence that addresses security fixes and implements new specification features.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to initialize a TUF client (`tuf.ngclient.Updater`) to securely fetch and verify a target file from a TUF repository. It assumes a `root.json` file is available out-of-band for initial trust bootstrapping and that a repository is serving metadata and targets. For a runnable example, you would need to set up a dummy TUF repository (e.g., using `tuf.repository` utilities, though it's not stable API, or a dedicated repository service like RSTUF) and provide a valid initial `root.json`.

import os
import shutil
from pathlib import Path
from tuf.ngclient import Updater

# --- Configuration (replace with your actual repository details) ---
REPO_METADATA_URL = os.environ.get('TUF_METADATA_URL', 'http://localhost:8000/metadata/')
REPO_TARGETS_URL = os.environ.get('TUF_TARGETS_URL', 'http://localhost:8000/targets/')

# Ensure a clean client state for demonstration
LOCAL_CACHE_DIR = Path('./client_cache')
LOCAL_DOWNLOAD_DIR = Path('./client_downloads')
ROOT_METADATA_PATH = Path('./initial_root.json')

if LOCAL_CACHE_DIR.exists():
    shutil.rmtree(LOCAL_CACHE_DIR)
if LOCAL_DOWNLOAD_DIR.exists():
    shutil.rmtree(LOCAL_DOWNLOAD_DIR)
LOCAL_CACHE_DIR.mkdir(parents=True, exist_ok=True)
LOCAL_DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)

# --- Simulate pre-packaged initial root metadata ---
# In a real application, this 'root.json' would be securely bundled
# with your application and stored in a read-only location.
# For this example, let's create a dummy one if it doesn't exist.
# You would typically copy a valid initial_root.json here.
if not ROOT_METADATA_PATH.exists():
    print("WARNING: Creating a dummy initial_root.json. "
          "In production, this file must be a trusted, pre-packaged root metadata.")
    with open(ROOT_METADATA_PATH, 'w') as f:
        f.write('{}') # Placeholder, will cause errors if not a real root.

print(f"Initializing TUF Updater with metadata_url='{REPO_METADATA_URL}' and targets_url='{REPO_TARGETS_URL}'")
print(f"Local cache: {LOCAL_CACHE_DIR}, Downloads: {LOCAL_DOWNLOAD_DIR}")

try:
    # Initialize TUF Updater
    updater = Updater(
        repository_dir=str(LOCAL_CACHE_DIR), # Local directory for storing metadata
        metadata_base_url=REPO_METADATA_URL,
        target_base_url=REPO_TARGETS_URL,
        initial_root_metadata=ROOT_METADATA_PATH.read_bytes() # Bootstrap trust from bundled root
    )

    # Refresh top-level metadata (root, timestamp, snapshot, targets)
    print("Refreshing top-level metadata...")
    updater.refresh()
    print("Metadata refreshed successfully.")

    # Get information about a target file
    TARGET_NAME = "example_target.txt" # Replace with an actual target name on your repo
    print(f"Getting target info for '{TARGET_NAME}'...")
    target_info = updater.get_targetinfo(TARGET_NAME)

    if target_info:
        print(f"Found target '{TARGET_NAME}' (size: {target_info.length} bytes, hashes: {target_info.hashes}).")
        # Download the target file
        target_path = LOCAL_DOWNLOAD_DIR / TARGET_NAME
        print(f"Downloading target to '{target_path}'...")
        updater.download_target(target_info, str(target_path))
        print(f"Target '{TARGET_NAME}' downloaded and verified successfully!")
    else:
        print(f"Target '{TARGET_NAME}' not found or could not be verified.")

except Exception as e:
    print(f"An error occurred: {e}")
    print("Please ensure a TUF repository is running at the configured URLs "
          "and that 'initial_root.json' is a valid, trusted root metadata file.")

view raw JSON →