{"id":9371,"library":"tuf","title":"The Update Framework (TUF) for Python","description":"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.","status":"active","version":"6.0.0","language":"en","source_language":"en","source_url":"https://github.com/theupdateframework/python-tuf","tags":["security","update framework","supply chain security","client","repository","metadata","package management"],"install":[{"cmd":"pip install tuf","lang":"bash","label":"Base installation"},{"cmd":"pip install \"securesystemslib[crypto]\" tuf","lang":"bash","label":"With full cryptographic abilities (for repository code)"}],"dependencies":[{"reason":"Provides core cryptographic routines; minimum v1.0.0 is required since tuf v5.0.0 for repository operations and full cryptographic capabilities.","package":"securesystemslib","optional":false},{"reason":"Default HTTP library used by ngclient since v6.0.0.","package":"urllib3","optional":false},{"reason":"Required only if explicitly using the deprecated RequestsFetcher for the ngclient.","package":"requests","optional":true}],"imports":[{"symbol":"Updater","correct":"from tuf.ngclient import Updater"},{"note":"Used for low-level metadata object manipulation.","symbol":"Metadata","correct":"from tuf.api.metadata import Metadata"},{"note":"Represents the Root metadata role object.","symbol":"Root","correct":"from tuf.api.metadata import Root"},{"note":"Represents information about a target file.","symbol":"TargetFile","correct":"from tuf.api.metadata import TargetFile"}],"quickstart":{"code":"import os\nimport shutil\nfrom pathlib import Path\nfrom tuf.ngclient import Updater\n\n# --- Configuration (replace with your actual repository details) ---\nREPO_METADATA_URL = os.environ.get('TUF_METADATA_URL', 'http://localhost:8000/metadata/')\nREPO_TARGETS_URL = os.environ.get('TUF_TARGETS_URL', 'http://localhost:8000/targets/')\n\n# Ensure a clean client state for demonstration\nLOCAL_CACHE_DIR = Path('./client_cache')\nLOCAL_DOWNLOAD_DIR = Path('./client_downloads')\nROOT_METADATA_PATH = Path('./initial_root.json')\n\nif LOCAL_CACHE_DIR.exists():\n    shutil.rmtree(LOCAL_CACHE_DIR)\nif LOCAL_DOWNLOAD_DIR.exists():\n    shutil.rmtree(LOCAL_DOWNLOAD_DIR)\nLOCAL_CACHE_DIR.mkdir(parents=True, exist_ok=True)\nLOCAL_DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)\n\n# --- Simulate pre-packaged initial root metadata ---\n# In a real application, this 'root.json' would be securely bundled\n# with your application and stored in a read-only location.\n# For this example, let's create a dummy one if it doesn't exist.\n# You would typically copy a valid initial_root.json here.\nif not ROOT_METADATA_PATH.exists():\n    print(\"WARNING: Creating a dummy initial_root.json. \"\n          \"In production, this file must be a trusted, pre-packaged root metadata.\")\n    with open(ROOT_METADATA_PATH, 'w') as f:\n        f.write('{}') # Placeholder, will cause errors if not a real root.\n\nprint(f\"Initializing TUF Updater with metadata_url='{REPO_METADATA_URL}' and targets_url='{REPO_TARGETS_URL}'\")\nprint(f\"Local cache: {LOCAL_CACHE_DIR}, Downloads: {LOCAL_DOWNLOAD_DIR}\")\n\ntry:\n    # Initialize TUF Updater\n    updater = Updater(\n        repository_dir=str(LOCAL_CACHE_DIR), # Local directory for storing metadata\n        metadata_base_url=REPO_METADATA_URL,\n        target_base_url=REPO_TARGETS_URL,\n        initial_root_metadata=ROOT_METADATA_PATH.read_bytes() # Bootstrap trust from bundled root\n    )\n\n    # Refresh top-level metadata (root, timestamp, snapshot, targets)\n    print(\"Refreshing top-level metadata...\")\n    updater.refresh()\n    print(\"Metadata refreshed successfully.\")\n\n    # Get information about a target file\n    TARGET_NAME = \"example_target.txt\" # Replace with an actual target name on your repo\n    print(f\"Getting target info for '{TARGET_NAME}'...\")\n    target_info = updater.get_targetinfo(TARGET_NAME)\n\n    if target_info:\n        print(f\"Found target '{TARGET_NAME}' (size: {target_info.length} bytes, hashes: {target_info.hashes}).\")\n        # Download the target file\n        target_path = LOCAL_DOWNLOAD_DIR / TARGET_NAME\n        print(f\"Downloading target to '{target_path}'...\")\n        updater.download_target(target_info, str(target_path))\n        print(f\"Target '{TARGET_NAME}' downloaded and verified successfully!\")\n    else:\n        print(f\"Target '{TARGET_NAME}' not found or could not be verified.\")\n\nexcept Exception as e:\n    print(f\"An error occurred: {e}\")\n    print(\"Please ensure a TUF repository is running at the configured URLs \"\n          \"and that 'initial_root.json' is a valid, trusted root metadata file.\")\n","lang":"python","description":"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`."},"warnings":[{"fix":"If you relied on `requests` being implicitly installed or want to continue using it, you must explicitly install `requests` and configure `Updater` to use the `RequestsFetcher` implementation. Otherwise, no action is needed for basic client usage.","message":"As of v6.0.0, `tuf.ngclient` uses `urllib3` as the default HTTP library instead of `requests`. This change removes implicit dependencies on `requests`, `idna`, `charset-normalizer`, and `certifi`.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Review the `securesystemslib` v1.0.0 release notes and `python-tuf` examples for updated DSSE API usage. The `ngclient` API was largely backwards-compatible for this change.","message":"tuf v5.0.0 introduced `securesystemslib v1.0.0` as a minimum requirement. This caused a minor break in the DSSE (Dead Simple Signing Envelope) API, particularly affecting users who directly depend on `securesystemslib`.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"If directly interacting with these methods in `tuf.api.metadata`, consult the v4.0.0 changelog and documentation to adapt to the new method signatures.","message":"TUF v4.0.0 changed the API for `Metadata API` users, specifically `Root.get_verification_result()` and `Targets.get_verification_result()`.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Avoid using `tuf.repository` in production systems where API stability is critical. Consider higher-level repository applications like RSTUF or `tuf-on-ci` for managing TUF repositories, or implement custom repository logic on top of `tuf.api.metadata`.","message":"The `tuf.repository` module is explicitly stated in the GitHub README as *not* being part of the `python-tuf` stable API.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Deploy `root.json` to system-wide read-only paths (e.g., `/usr/share/your-app/root.json`), application bundles, or read-only mounted volumes. Do *not* store it in the client's metadata cache directory as it is writable by design.","message":"The initial trusted root metadata (`root.json`) is the critical trust anchor. It should be provided to the client application and stored in a *read-only* location to prevent tampering.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"If your application explicitly relies on the `RequestsFetcher` (which is now deprecated), install `requests` explicitly: `pip install requests`. Otherwise, `tuf.ngclient` will use `urllib3` by default.","cause":"Upgrading to `tuf` v6.0.0 without accounting for the switch from `requests` to `urllib3` as the default HTTP client for `ngclient`.","error":"ModuleNotFoundError: No module named 'requests'"},{"fix":"Ensure the `initial_root_metadata` argument to `Updater` (or the file path provided) points to a correctly formatted and trusted `root.json` file. Validate the JSON structure and its contents against the TUF specification.","cause":"The initial root metadata file provided to the `Updater` is malformed, corrupted, or not a valid TUF root metadata file.","error":"RepositoryError: Local root.json is invalid."},{"fix":"Ensure the `repository_dir` provided to `Updater` is writable by the user running the client. For the initial trusted `root.json`, store it in a securely managed, typically read-only, path and pass its content via `initial_root_metadata`.","cause":"The TUF client attempts to write or update metadata in a directory where the running user lacks write permissions, or the cached root metadata is in a read-only location.","error":"Permission denied: '.../.sigstore/root.json'"},{"fix":"Verify the integrity and correctness of the metadata file. Ensure it conforms to the TUF specification for the respective role (e.g., `_type` should be 'root', 'targets', 'snapshot', or 'timestamp').","cause":"Attempting to load or parse a TUF metadata file (`root.json`, `targets.json`, etc.) with an invalid `_type` field within its signed payload, or a corrupted file.","error":"ValueError: unrecognized metadata type \"<UNKNOWN_TYPE>\""}]}