Skip to content

Commit 5c8672c

Browse files
authored
Release 3.2.1: keep the signing key out of the malformed-JWK error (#165)
## Summary Maintenance sweep for python-commerce, released as 3.2.1 because it carries one fix to shipped code (the Python mirror of node-commerce 3.1.2). **Fix: the signing key no longer travels with the malformed-JWK error.** `load_ucp_signing_key_from_env` raised its "is not valid JSON" `ValueError` `from` the `JSONDecodeError`, and that error keeps the whole input in `.doc`, which here is the private JWK. Anything that records chained exceptions (an error tracker, a traceback with locals) received the key. The error now names the variable only and raises `from None`. Sweep: - Relocked to current: fastapi 0.146.0, starlette 1.9.0, cdp-sdk 1.50.0, joserfc 1.7.7, pydantic-settings 2.16.0, httpx2 and httpcore2 2.14.0, ruff 0.17.1, ty 0.0.89, plus certifi, pluggy, wrapt, truststore, bitarray and lefthook. The only prereleases in the lock are the three OpenTelemetry packages that have never shipped a stable release, unchanged from main. - The uv pin in ci, publish and security moves from 0.13.0 to 0.13.1. - The lint and type gate job runs on Python 3.15 (`uv sync --python 3.15`, so the job uses that interpreter rather than whichever one uv finds first), and so does the pip-audit job. The test matrix still covers 3.11 through 3.15. Worked with Varun, as part of a three-session maintenance sweep. Not done, on purpose: the `web3<8` constraint stays. Its lift condition was re-tested: pympp 0.14.0 still requires `eth-abi<6` in both its `tempo` and `stripe` extras. Optional-extra floors are unchanged, since the published ranges already admit the new versions. ## Type of change - [x] Bug fix (no breaking change) - [ ] New feature (no breaking change) - [ ] Breaking change (existing callers must update) - [ ] Docs, tests, or internal maintenance only ## Public API The malformed-JWK error's message is now `UCP_SIGNING_KEY_JWK_PRIVATE is not valid JSON.` (or the configured variable name) without the decoder's position detail, and it no longer chains the `JSONDecodeError`. The exception type is unchanged. ## Test plan A new test feeds a malformed value and asserts the message carries no part of it, `__cause__` is None and the context is suppressed. It fails against the previous `ucp_jwks.py` and passes with the fix. Run locally on Python 3.15: ruff check, ruff format --check, ty (package and examples), vulture and pytest (1674 passed, 4 skipped), each exit 0. osv-scanner 2.7.0 over uv.lock reports no issues across 164 packages. ## Checklist - [x] Tests cover the new behavior, and the suite passes locally - [x] Lint, format, and type checks pass - [x] Docs and README examples updated if the public surface changed - [x] No secrets, credentials, or personal data in the diff or the tests
1 parent 4f64ff0 commit 5c8672c

7 files changed

Lines changed: 294 additions & 268 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ jobs:
2424
- name: Install uv
2525
uses: astral-sh/setup-uv@v10.3.0
2626
with:
27-
version: "0.13.0"
27+
version: "0.13.1"
2828

2929
- name: Set up Python
30-
run: uv python install 3.12
30+
run: uv python install 3.15
3131

3232
- uses: actions/cache@v6
3333
with:
@@ -38,7 +38,7 @@ jobs:
3838
restore-keys: ${{ runner.os }}-uv-
3939

4040
- name: Install dependencies
41-
run: uv sync --frozen --all-extras
41+
run: uv sync --frozen --all-extras --python 3.15
4242

4343
- name: Ruff check
4444
run: uv run ruff check .
@@ -71,7 +71,7 @@ jobs:
7171
- name: Install uv
7272
uses: astral-sh/setup-uv@v10.3.0
7373
with:
74-
version: "0.13.0"
74+
version: "0.13.1"
7575

7676
- name: Set up Python
7777
run: uv python install ${{ matrix.python }}

‎.github/workflows/publish.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121

2222
- uses: astral-sh/setup-uv@v10.3.0
2323
with:
24-
version: "0.13.0"
24+
version: "0.13.1"
2525

2626
- name: Set version from tag
2727
run: sed -i "s/^version = .*/version = \"${GITHUB_REF_NAME#v}\"/" pyproject.toml

‎.github/workflows/security.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ jobs:
4141
- uses: useblacksmith/checkout@v1
4242
- uses: astral-sh/setup-uv@v10.3.0
4343
with:
44-
version: "0.13.0"
44+
version: "0.13.1"
4545
- uses: actions/setup-python@v7
4646
with:
47-
python-version: "3.14"
47+
python-version: "3.15"
4848

4949
- name: Install pip-audit
5050
run: pip install pip-audit

‎agentscore_commerce/identity/ucp_jwks.py‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -583,9 +583,11 @@ def _build_env_signing_key(
583583

584584
try:
585585
jwk_dict = json.loads(env_jwk)
586-
except json.JSONDecodeError as exc:
587-
msg = f"{env_jwk_var} is not valid JSON: {exc}"
588-
raise ValueError(msg) from exc
586+
except json.JSONDecodeError:
587+
# The decode error holds the whole value in ``.doc``, which here is
588+
# private key material, so it is not chained onto what is raised.
589+
msg = f"{env_jwk_var} is not valid JSON."
590+
raise ValueError(msg) from None
589591

590592
if not isinstance(jwk_dict, dict) or not jwk_dict:
591593
msg = f"{env_jwk_var} must be a non-empty JWK object; got {type(jwk_dict).__name__}."

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "agentscore-commerce"
7-
version = "3.2.0"
7+
version = "3.2.1"
88
description = "Agentic commerce SDK for Python: identity middleware (FastAPI, Flask, Django, AIOHTTP, Sanic, ASGI) + payment helpers + 402 builders + discovery + Stripe multichain. The full merchant-side toolkit for AgentScore-powered agentic commerce."
99
readme = "README.md"
1010
license = "MIT"

‎tests/test_load_ucp_signing_key_from_env.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,15 @@ def test_malformed_json_raises_naming_env_var(monkeypatch) -> None:
191191
load_ucp_signing_key_from_env()
192192

193193

194+
def test_malformed_json_keeps_env_value_out_of_the_error(monkeypatch) -> None:
195+
monkeypatch.setenv("UCP_SIGNING_KEY_JWK_PRIVATE", '{"secret":SENSITIVEBYTES}')
196+
with pytest.raises(ValueError) as info:
197+
load_ucp_signing_key_from_env()
198+
assert "SENSITIVE" not in str(info.value)
199+
assert info.value.__cause__ is None
200+
assert info.value.__suppress_context__ is True
201+
202+
194203
def test_unsupported_kty_crv_raises_naming_actual(monkeypatch) -> None:
195204
monkeypatch.setenv(
196205
"UCP_SIGNING_KEY_JWK_PRIVATE",

‎uv.lock‎

Lines changed: 272 additions & 257 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)