Skip to main content

Python client library for the Transparency Exchange API (TEA)

Project description

libtea

CI PyPI version Python License

Python client library for the Transparency Exchange API (TEA) v0.3.0-beta.2.

TEA is an open standard for discovering and retrieving software transparency artifacts (SBOMs, VEX, build metadata) for any software product or component. A TEI identifier resolves via DNS to the right endpoint, similar to how email uses MX records — so consumers can fetch artifacts without knowing which server hosts them.

Specification: Ecma TC54-TG1 | OpenAPI spec

Status: Alpha — API is subject to change.

Features

  • Auto-discovery via .well-known/tea and TEI URNs
  • Products, components, releases, and versioned collections
  • Search by PURL, CPE, or TEI identifier
  • Artifact download with on-the-fly checksum verification (MD5 through BLAKE2b)
  • Typed Pydantic v2 models with full camelCase/snake_case conversion
  • Structured exception hierarchy with error context
  • Bearer token isolation — tokens are never sent to artifact download hosts

Installation

pip install libtea

Quick start

from libtea import TeaClient

# Auto-discover from a domain's .well-known/tea
with TeaClient.from_well_known("example.com", token="your-bearer-token") as client:
    # Browse a product
    product = client.get_product("product-uuid")
    print(product.name)

    # Get a component release with its latest collection
    cr = client.get_component_release("release-uuid")
    for artifact in cr.latest_collection.artifacts:
        print(artifact.name, artifact.type)

Or connect directly to a known endpoint:

client = TeaClient(
    base_url="https://api.example.com/tea/v0.3.0-beta.2",
    token="your-bearer-token",
    timeout=30.0,
)

Using from_well_known, you can also override the spec version and timeout:

client = TeaClient.from_well_known(
    "example.com",
    token="your-bearer-token",
    timeout=15.0,
    version="0.3.0-beta.2",  # default
)

Usage

Search

with TeaClient.from_well_known("example.com") as client:
    # Search by PURL
    results = client.search_products("PURL", "pkg:pypi/requests")
    for product in results.results:
        print(product.name, product.uuid)

    # Search product releases (with pagination)
    releases = client.search_product_releases(
        "PURL", "pkg:pypi/requests@2.31.0",
        page_offset=0, page_size=100,
    )
    print(releases.total_results)

Products and releases

with TeaClient.from_well_known("example.com") as client:
    product = client.get_product("product-uuid")
    print(product.name, product.identifiers)

    releases = client.get_product_releases("product-uuid", page_size=25)
    for release in releases.results:
        print(release.version, release.created_date)

    # Single product release
    pr = client.get_product_release("release-uuid")
    print(pr.version, pr.components)

    # Product release collections
    latest = client.get_product_release_collection_latest("release-uuid")
    all_versions = client.get_product_release_collections("release-uuid")
    specific = client.get_product_release_collection("release-uuid", 3)

Components

with TeaClient(base_url="https://api.example.com/tea/v0.3.0-beta.2") as client:
    component = client.get_component("component-uuid")
    releases = client.get_component_releases("component-uuid")

    # Get a component release with its latest collection
    cr = client.get_component_release("release-uuid")
    print(cr.release.version, len(cr.latest_collection.artifacts))

Collections and artifacts

with TeaClient(base_url="https://api.example.com/tea/v0.3.0-beta.2") as client:
    collection = client.get_component_release_collection_latest("release-uuid")
    for artifact in collection.artifacts:
        print(artifact.name, artifact.type)

    # All collection versions for a component release
    all_versions = client.get_component_release_collections("release-uuid")

    # Specific collection version
    collection_v3 = client.get_component_release_collection("release-uuid", 3)

Downloading artifacts with checksum verification

from pathlib import Path

with TeaClient(base_url="https://api.example.com/tea/v0.3.0-beta.2") as client:
    artifact = client.get_artifact("artifact-uuid")
    fmt = artifact.formats[0]

    # Downloads and verifies checksums on-the-fly; returns the dest path
    path = client.download_artifact(
        fmt.url,
        Path("sbom.json"),
        verify_checksums=fmt.checksums,
    )

Supported checksum algorithms: MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512, BLAKE2b-256, BLAKE2b-384, BLAKE2b-512. BLAKE3 is recognized in the model but not verifiable (Python's hashlib has no BLAKE3 support — a clear error is raised).

Artifact downloads use a separate unauthenticated HTTP session so the bearer token is never leaked to third-party hosts (CDNs, Maven Central, etc.). On checksum mismatch, the downloaded file is automatically deleted.

Discovery

from libtea.discovery import parse_tei, fetch_well_known, select_endpoint

# Parse a TEI URN
tei_type, domain, identifier = parse_tei(
    "urn:tei:purl:cyclonedx.org:pkg:pypi/cyclonedx-python-lib@8.4.0"
)

# Low-level: fetch and select an endpoint manually
well_known = fetch_well_known("example.com")
endpoint = select_endpoint(well_known, "0.3.0-beta.2")
print(endpoint.url, endpoint.priority)

# Discover product releases by TEI
with TeaClient(base_url="https://api.example.com/tea/v0.3.0-beta.2") as client:
    results = client.discover("urn:tei:uuid:example.com:d4d9f54a-abcf-11ee-ac79-1a52914d44b")
    for info in results:
        print(info.product_release_uuid, info.servers)

Supported TEI types: uuid, purl, hash, swid, eanupc, gtin, asin, udi.

Error handling

All exceptions inherit from TeaError:

from libtea.exceptions import TeaError, TeaNotFoundError, TeaChecksumError

try:
    product = client.get_product("unknown-uuid")
except TeaNotFoundError as exc:
    print(exc.error_type)  # "OBJECT_UNKNOWN" or "OBJECT_NOT_SHAREABLE"
except TeaError:
    print("Something went wrong")

Exception hierarchy:

Exception When
TeaConnectionError Network failure or timeout
TeaAuthenticationError HTTP 401/403
TeaNotFoundError HTTP 404 (.error_type has the TEA error code)
TeaRequestError Other HTTP 4xx
TeaServerError HTTP 5xx
TeaDiscoveryError Invalid TEI, .well-known failure, or no compatible endpoint
TeaChecksumError Checksum mismatch (.algorithm, .expected, .actual)
TeaValidationError Malformed server response
TeaInsecureTransportWarning Warning emitted when using plaintext HTTP

Using a bearer token over plaintext HTTP raises ValueError immediately — HTTPS is required for authenticated requests.

Requirements

Not yet supported

  • Publisher API (spec is consumer-only in beta.2)
  • Async client
  • CLE (Common Lifecycle Enumeration) endpoints
  • Mutual TLS (mTLS) authentication
  • Endpoint failover with retry

Development

This project uses uv for dependency management.

uv sync                        # Install dependencies
uv run pytest                  # Run tests (with coverage)
uv run ruff check .            # Lint
uv run ruff format --check .   # Format check
uv build                       # Build wheel and sdist

License

Apache 2.0 — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

libtea-0.1.1.tar.gz (76.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

libtea-0.1.1-py3-none-any.whl (22.1 kB view details)

Uploaded Python 3

File details

Details for the file libtea-0.1.1.tar.gz.

File metadata

  • Download URL: libtea-0.1.1.tar.gz
  • Upload date:
  • Size: 76.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for libtea-0.1.1.tar.gz
Algorithm Hash digest
SHA256 c5197e3992521a182d5f6af1bf75f851a619e5ba61d616bdebd438537beff202
MD5 aae6c8eec0ffaf29952fd91d3a4d6072
BLAKE2b-256 7a5ffbf7eae3d7589a7b9c27632a630f90eca5b455ddfebd98812ddf64935883

See more details on using hashes here.

Provenance

The following attestation bundles were made for libtea-0.1.1.tar.gz:

Publisher: pypi.yaml on sbomify/py-libtea

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file libtea-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: libtea-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 22.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for libtea-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7b77cc606040152f2bd84f1a9aa59fa09490a7e8e988543850703f08c4caed7c
MD5 9778033e93f8142fd5436415586643c2
BLAKE2b-256 8ff39ac0c2f404275134f0bb3160e425d293ec01534fb4c12d11b6d0b30479e6

See more details on using hashes here.

Provenance

The following attestation bundles were made for libtea-0.1.1-py3-none-any.whl:

Publisher: pypi.yaml on sbomify/py-libtea

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page