Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
ccd88eb
build: bump to v0.2.0, add semver dep and cli optional extra
aurangzaib048 Feb 26, 2026
663e613
refactor: replace all regexes with plain string operations
aurangzaib048 Feb 26, 2026
f8ccb55
fix: add DiscoveryInfo.servers min_length per spec
aurangzaib048 Feb 26, 2026
03dd536
fix: address review findings from comprehensive code review
aurangzaib048 Feb 26, 2026
1518040
feat: add scheme and port params to fetch_well_known
aurangzaib048 Feb 26, 2026
32021ae
feat: add CLE models (CLEEvent, CLEEventType, CLE, etc.)
aurangzaib048 Feb 26, 2026
500dd78
feat: add 4 CLE endpoint methods to TeaClient
aurangzaib048 Feb 26, 2026
0a00de3
fix: address Batch 2 review findings
aurangzaib048 Feb 26, 2026
49e9ba9
feat: add basic auth, mTLS, retry with exponential backoff
aurangzaib048 Feb 26, 2026
fbc9cf3
refactor: replace custom _SemVer with semver.Version
aurangzaib048 Feb 26, 2026
63da3b9
feat: add tea-cli with typer (discover, search, get, download, inspect)
aurangzaib048 Feb 26, 2026
078605a
fix: address review findings from Batch 3
aurangzaib048 Feb 26, 2026
4f7286c
fix: address all remaining review findings (P0-P3)
aurangzaib048 Feb 26, 2026
acce2d4
fix: skip CLI tests when typer not installed
aurangzaib048 Feb 26, 2026
77565f5
Harden security, align models with TEA spec, and expand test coverage
aurangzaib048 Feb 26, 2026
370fe5f
Harden SSRF protection, fix spec alignment, and improve validation
aurangzaib048 Feb 26, 2026
a312065
Add v0.3.0 design doc and FUTURE.md for spec-blocked items
aurangzaib048 Feb 26, 2026
eca0cff
Add missing CLE event type tests and improve CLAUDE.md
aurangzaib048 Feb 27, 2026
503b1cf
Address PR review comments from Copilot
aurangzaib048 Feb 27, 2026
94f5e38
Enhance component release handling and validation
aurangzaib048 Feb 27, 2026
f77759c
Enhance TEI handling in CLI
aurangzaib048 Feb 27, 2026
7fc6d94
Fix review findings: remove dead code, modernize syntax, harden CI, a…
aurangzaib048 Feb 27, 2026
8832af4
Improve docstrings across all library modules
aurangzaib048 Feb 27, 2026
8fe8d50
Use 'UUID' consistently in model Attributes docstrings
aurangzaib048 Feb 27, 2026
9a46830
Enforce RFC 4122 UUID validation per TEA spec
aurangzaib048 Feb 27, 2026
5d65338
Update CI workflow to include additional CLI options for synchronization
aurangzaib048 Feb 27, 2026
91623d7
Add rich-formatted CLI output with --json fallback
aurangzaib048 Feb 27, 2026
a6a38fc
Address PR review findings: UUID normalization, probe cleanup, entry-…
aurangzaib048 Feb 27, 2026
b2d2161
Add --debug and --quiet flags inspired by rearm CLI
aurangzaib048 Feb 27, 2026
ccee499
Enrich CLI inspect output and complete TEA spec field coverage
aurangzaib048 Feb 27, 2026
3fd1de2
Add missing CLI commands for full TEA API coverage
aurangzaib048 Feb 27, 2026
807d8ab
Fix help text assertions to strip ANSI escape codes
aurangzaib048 Feb 27, 2026
2cc2c20
Update README with sbomify examples and add tea-cli man page
aurangzaib048 Feb 27, 2026
d16ff87
Replace troff man page with markdown CLI reference
aurangzaib048 Feb 27, 2026
4943651
Address PR review findings: harden CLI and rich output
aurangzaib048 Feb 27, 2026
4e3ed36
Fix SSRF bypass, harden error handling, and fill test coverage gaps
aurangzaib048 Feb 27, 2026
6c96073
Address PR review: move probe to HTTP layer, wrap discovery ValueError
aurangzaib048 Feb 27, 2026
f89f9ce
Fix README field names, remove misplaced SSRF check, bound error body…
aurangzaib048 Feb 27, 2026
dd8d6c9
Add SSRF protection for discovery redirects in fetch_well_known()
aurangzaib048 Feb 27, 2026
f186c5a
Update CLAUDE.md architecture and design patterns
aurangzaib048 Feb 27, 2026
9658935
Restructure library: src/ layout, extract modules, reorganize tests
aurangzaib048 Feb 27, 2026
dc67f4c
Fix pyproject.toml path in test after cli/ subdirectory move
aurangzaib048 Feb 27, 2026
a9f19ac
Add in-process test for _cli_entry ImportError branch
aurangzaib048 Feb 27, 2026
0cb5417
Add mypy strict type checking with pydantic plugin
aurangzaib048 Feb 27, 2026
e515751
Address PR review: probe redirects, response cleanup, failover errors…
aurangzaib048 Feb 27, 2026
0074101
Close download response on all paths, use tuples for true model immut…
aurangzaib048 Feb 28, 2026
a9bd30f
Fix off-by-one in download redirect loop
aurangzaib048 Feb 28, 2026
0a79a21
Fix SSRF in fetch_well_known by following redirects manually with per…
aurangzaib048 Feb 28, 2026
d395e06
Close discovery response on all paths, use current_url in error messages
aurangzaib048 Feb 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
- run: uv python install ${{ matrix.python-version }}
- run: uv sync
- run: uv sync --extra cli
- run: uv run ruff check .
- run: uv run ruff format --check .
- run: uv run pytest --cov=libtea --cov-report=term-missing
- run: uv run pytest --cov-fail-under=90
- run: uv build
5 changes: 5 additions & 0 deletions .github/workflows/pypi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ jobs:

- uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0

- name: Run tests
run: |
uv sync --extra cli
uv run pytest --cov-fail-under=90

- name: Build package
run: uv build

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ htmlcov/
nosetests.xml
coverage.xml
*.cover
*,cover
*.py.cover
.hypothesis/
.pytest_cache/
Expand Down
10 changes: 9 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.0
rev: v0.15.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: local
hooks:
- id: mypy
name: mypy
entry: uv run mypy
language: system
types: [python]
pass_filenames: false
95 changes: 79 additions & 16 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,90 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

**py-libtea** is a Python client library for the Transparency Exchange API (TEA), maintained under the sbomify organization.

- **License**: Apache 2.0
- **Repository**: https://github.com/sbomify/py-libtea
**py-libtea** is a hand-crafted Python client library for the Transparency Exchange API (TEA) v0.3.0-beta.2. Consumer-focused (read-only); publisher API is not yet supported (blocked on TEA spec). Licensed Apache 2.0, maintained under sbomify.

## Build & Dev Commands

```bash
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
uv sync # Install all dependencies
uv run pytest # Run full test suite with coverage
uv run pytest tests/client/test_client.py -v # Run a single test file
uv run pytest tests/unit/test_security.py::TestSsrfProtection::test_rejects_cgnat_ip -v # Single test
uv run mypy # Type check (strict mode)
uv run ruff check . # Lint
uv run ruff format --check . # Format check
uv run ruff format . # Auto-format
uv build # Build wheel and sdist
```

## Code Conventions

- **Layout**: Flat package layout (`libtea/`)
- **Build backend**: Hatchling
- **Line length**: 120
- **Lint/Format**: Ruff (rules: E, F, I)
- **Tests**: pytest with pytest-cov, test files in `tests/`
- **Python**: >=3.11
- **Type checking**: PEP 561 (`py.typed` marker)
- **Layout**: src/ layout (`src/libtea/`), hatchling build backend
- **Python**: >=3.11 (enables `StrEnum`, `X | Y` union syntax)
- **Line length**: 120, ruff rules: E, F, I
- **Models**: Pydantic v2 with `frozen=True`, `extra="ignore"`, `alias_generator=to_camel`
- **HTTP mocking**: `responses` library (not `unittest.mock` for HTTP)
- **Coverage**: Branch coverage enabled, target ~97%

## Architecture

The library has a layered design with strict separation of concerns:

```
__init__.py Public API re-exports (all models, exceptions, client, discovery)
client.py TeaClient — high-level consumer API, checksum verification
↓ uses
_validation.py Input validation helpers (path segments, page size/offset, Pydantic wrappers)
_http.py TeaHttpClient — low-level requests wrapper, auth, streaming downloads
Also: probe_endpoint() for endpoint failover
_security.py SSRF protection (_validate_download_url, DNS rebinding checks, internal IP detection)
_hashing.py Checksum hash builders (SHA-*, BLAKE2b-*, MD5)
discovery.py TEI parsing, .well-known/tea fetching, SemVer endpoint selection, redirect SSRF protection
models.py Pydantic v2 models for all TEA domain objects (frozen, camelCase aliases)
exceptions.py Exception hierarchy (all inherit from TeaError)
cli.py typer CLI (optional dependency, thin wrapper over TeaClient)
_cli_fmt.py Rich output formatters for all CLI commands (tables, panels, escape helpers)
_cli_entry.py Entry point wrapper that handles missing typer gracefully
```

**Key design patterns:**

- `TeaClient` delegates all HTTP to `TeaHttpClient` — never calls `requests` directly
- Bearer tokens are NOT sent to artifact download URLs (separate unauthenticated session prevents token leakage to CDNs)
- Downloads follow redirects manually with SSRF validation at each hop
- Discovery redirects are validated against internal networks (SSRF protection via `_security._validate_download_url`)
- `_validation._validate()` wraps Pydantic `ValidationError` into `TeaValidationError` so all client errors are `TeaError` subclasses
- Endpoint failover: `from_well_known()` probes candidates in priority order, skipping unreachable ones
- `probe_endpoint()` lives in `_http.py` (not `client.py`) to maintain the HTTP layer boundary
- `_raise_for_status()` uses bounded reads (201 bytes) for error body snippets to avoid memory issues on streaming responses
- CLI formatters in `_cli_fmt.py` escape all server-controlled strings with `rich.markup.escape()` to prevent Rich markup injection

**Auth**: Bearer token, basic auth, and mTLS (via `MtlsConfig` dataclass) are mutually configurable. Token and basic_auth are mutually exclusive. HTTP (non-TLS) with credentials is rejected.

## Critical Implementation Rules

- **NEVER** use `from __future__ import annotations` in files containing Pydantic models — it breaks Pydantic v2 runtime type evaluation
- `pydantic >= 2.1.0` is the floor (for `pydantic.alias_generators.to_camel`)
- `requests` auto-encodes query params — do NOT pre-encode with `urllib.parse.quote()`
- When mocking with `responses` library, use `requests.ConnectionError` as the body exception (not Python's built-in `ConnectionError` — they are different classes)
- `ChecksumAlgorithm` values may arrive as `SHA_256` (underscore) or `SHA-256` (hyphen) from servers — the `@field_validator` in `Checksum` normalizes both
- BLAKE3 is in the enum for spec completeness but NOT supported at runtime (not in stdlib `hashlib`) — raises `TeaChecksumError`
- `Identifier.id_type` is typed as `str` (not `IdentifierType` enum) so unknown types from future spec versions pass through
- CGNAT range (100.64.0.0/10, RFC 6598) is checked separately in SSRF protection because `ipaddress.is_private` misses it on Python 3.11+

## TEA Spec Reference

The TEA spec repo should be cloned to `/tmp/transparency-exchange-api/` for cross-referencing:

```bash
git clone https://github.com/CycloneDX/transparency-exchange-api /tmp/transparency-exchange-api
```

Key spec files: `spec/openapi.yaml`, `discovery/readme.md`, `auth/readme.md`

## Design Docs

- `docs/plans/2025-02-25-tea-client-design.md` — v0.1.0 original design
- `docs/plans/2026-02-25-v0.2.0-design.md` — v0.2.0 (CLE, SemVer, failover, mTLS, CLI)
- `docs/plans/2026-02-26-v0.3.0-design.md` — v0.3.0 (httpx migration, async client)
- `docs/FUTURE.md` — Items blocked on external factors (Publisher API)
Loading