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.
- Auto-discovery via
.well-known/teaand 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
pip install libteafrom 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
)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)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)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))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)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.
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.
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.
- Publisher API (spec is consumer-only in beta.2)
- Async client
- CLE (Common Lifecycle Enumeration) endpoints
- Mutual TLS (mTLS) authentication
- Endpoint failover with retry
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 sdistApache 2.0 — see LICENSE for details.