Skip to content

feat: add load_ucp_signing_key_from_env helper - #28

Merged
vvillait88 merged 1 commit into
mainfrom
tec-302-ucp-env-loader
May 14, 2026
Merged

feat: add load_ucp_signing_key_from_env helper#28
vvillait88 merged 1 commit into
mainfrom
tec-302-ucp-env-loader

Conversation

@vvillait88

Copy link
Copy Markdown
Contributor

Summary

  • Env-driven UCP signing-key loader with concurrent-safe caching. Reads `UCP_SIGNING_KEY_JWK_PRIVATE`, validates kty/crv (OKP+Ed25519 or EC+P-256), projects to canonical public JWK. Falls back to ephemeral keypair when absent.
  • Largest single lift of TEC-302: replaces 3 structurally identical implementations (~385 lines combined across store/lib/ucp_signing.py, martin/lib/ucp-signing.ts, signed_ucp_merchant.py inline).
  • Cache keyed by full options tuple — merchants running multiple keys from different env namespaces don't collide.
  • Error messages sanitize underlying joserfc exceptions; key bytes never leak to logs.

Behavior contract

  • Embedded `kid` in JWK wins over env `kid`; empty-string falls through to default.
  • Structural `kty`+`crv` wins over env alg.
  • Whitespace-only env var treated as absent (handles xargs-newline footgun).
  • Case-insensitive env alg comparison.
  • Concurrent first-callers share cached result (threading.Lock-protected).

Tests

  • 22 locked behavior contracts shared with the `@agent-score/commerce` sibling.
  • Env-load happy paths (Ed25519 + ES256), kid precedence, unknown-field stripping, ephemeral fallback, whitespace handling, malformed-input errors, sanitized-error invariant, caching identity, concurrent-call safety, env-var override.

Test plan

  • `uv run pytest tests/test_load_ucp_signing_key_from_env.py` — 22 tests pass
  • `uv run pytest` — full suite 1024 pass / 3 skip, coverage 95.24%
  • `uv run ruff check`, `uv run ruff format --check`, `uv run ty check` — green

🤖 Generated with Claude Code

Env-driven UCP signing-key loader with concurrent-safe caching. Reads
UCP_SIGNING_KEY_JWK_PRIVATE, parses as a JWK, validates kty/crv (OKP+Ed25519
or EC+P-256), and projects to a canonical public JWK. Falls back to an
ephemeral keypair when the env var is missing or whitespace-only.

Three structurally identical copies of this pattern exist today across
core/store/store/lib/ucp_signing.py, martin-estate/src/lib/ucp-signing.ts,
and python-commerce/examples/signed_ucp_merchant.py — all collapse to a
single load_ucp_signing_key_from_env() call in follow-up migrations.

Env-driven precedence: embedded kid in JWK wins over env kid; empty-string
kid falls through to options default. Structural kty+crv wins over env alg.
Case-insensitive env-alg comparison. Caching keyed by all 5 options fields
so a merchant running multiple keys from different env namespaces doesn't
collide. Concurrent first-callers share cached result (lock-protected).

Error messages name the env var and sanitize underlying joserfc exceptions
— class name only, never the raw message, so key bytes never reach
stderr/CloudWatch.

Tests lock 22 behavior contracts shared with the Node sibling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vvillait88
vvillait88 merged commit e3bb4e5 into main May 14, 2026
7 checks passed
@vvillait88
vvillait88 deleted the tec-302-ucp-env-loader branch May 14, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant