diff --git a/agentscore_commerce/identity/__init__.py b/agentscore_commerce/identity/__init__.py index 18fd015..7b7baed 100644 --- a/agentscore_commerce/identity/__init__.py +++ b/agentscore_commerce/identity/__init__.py @@ -23,7 +23,7 @@ build_a2a_agent_card, ucp_a2a_extension, ) -from agentscore_commerce.identity.client import GateClient +from agentscore_commerce.identity.core import AgentScoreCore from agentscore_commerce.identity.policy import ( EnforcementMode, GateResult, @@ -106,6 +106,7 @@ def _load_asgi_middleware() -> tuple[Any, Any]: "A2AAgentSkill", "AgentIdentity", "AgentMemoryHint", + "AgentScoreCore", "AgentScoreGate", "AgentScoreGatePolicy", "AssessResult", @@ -113,7 +114,6 @@ def _load_asgi_middleware() -> tuple[Any, Any]: "DenialCode", "DenialReason", "EnforcementMode", - "GateClient", "GateResult", "GeneratedUCPKey", "IdentityStatus", diff --git a/agentscore_commerce/identity/aiohttp.py b/agentscore_commerce/identity/aiohttp.py index 7fe0a16..fcf14c0 100644 --- a/agentscore_commerce/identity/aiohttp.py +++ b/agentscore_commerce/identity/aiohttp.py @@ -19,8 +19,8 @@ build_missing_identity_reason, denial_reason_to_body, ) -from agentscore_commerce.identity.client import ( - GateClient, +from agentscore_commerce.identity.core import ( + AgentScoreCore, InvalidCredentialError, PaymentRequiredError, QuotaExceededError, @@ -163,7 +163,7 @@ def agentscore_gate_middleware( """ from aiohttp import web - client = GateClient( + client = AgentScoreCore( api_key=api_key, require_kyc=require_kyc, require_sanctions_clear=require_sanctions_clear, diff --git a/agentscore_commerce/identity/client.py b/agentscore_commerce/identity/core.py similarity index 99% rename from agentscore_commerce/identity/client.py rename to agentscore_commerce/identity/core.py index e3f04cc..6ded865 100644 --- a/agentscore_commerce/identity/client.py +++ b/agentscore_commerce/identity/core.py @@ -55,7 +55,7 @@ DEFAULT_CACHE_SECONDS = 300 -class GateClient: +class AgentScoreCore: """Shared client for calling the AgentScore assess API. Manages caching and policy construction. Used by all framework adapters. diff --git a/agentscore_commerce/identity/django.py b/agentscore_commerce/identity/django.py index 3efa46b..69e036a 100644 --- a/agentscore_commerce/identity/django.py +++ b/agentscore_commerce/identity/django.py @@ -20,8 +20,8 @@ build_missing_identity_reason, denial_reason_to_body, ) -from agentscore_commerce.identity.client import ( - GateClient, +from agentscore_commerce.identity.core import ( + AgentScoreCore, InvalidCredentialError, PaymentRequiredError, QuotaExceededError, @@ -129,7 +129,7 @@ def __init__(self, get_response: Any) -> None: config: dict[str, Any] = getattr(settings, "AGENTSCORE_GATE", {}) - self._client = GateClient( + self._client = AgentScoreCore( api_key=config.get("api_key", ""), require_kyc=config.get("require_kyc"), require_sanctions_clear=config.get("require_sanctions_clear"), diff --git a/agentscore_commerce/identity/fastapi.py b/agentscore_commerce/identity/fastapi.py index b7a5180..8585b3a 100644 --- a/agentscore_commerce/identity/fastapi.py +++ b/agentscore_commerce/identity/fastapi.py @@ -26,8 +26,8 @@ build_missing_identity_reason, denial_reason_to_body, ) -from agentscore_commerce.identity.client import ( - GateClient, +from agentscore_commerce.identity.core import ( + AgentScoreCore, InvalidCredentialError, PaymentRequiredError, QuotaExceededError, @@ -181,7 +181,7 @@ def __init__( on_denied: Callable[[Request, DenialReason], tuple[dict[str, Any], int]] | None = None, create_session_on_missing: CreateSessionOnMissing | None = None, ) -> None: - self._client = GateClient( + self._client = AgentScoreCore( api_key=api_key, require_kyc=require_kyc, require_sanctions_clear=require_sanctions_clear, diff --git a/agentscore_commerce/identity/flask.py b/agentscore_commerce/identity/flask.py index 47049fc..be0aba5 100644 --- a/agentscore_commerce/identity/flask.py +++ b/agentscore_commerce/identity/flask.py @@ -19,8 +19,8 @@ build_missing_identity_reason, denial_reason_to_body, ) -from agentscore_commerce.identity.client import ( - GateClient, +from agentscore_commerce.identity.core import ( + AgentScoreCore, InvalidCredentialError, PaymentRequiredError, QuotaExceededError, @@ -167,7 +167,7 @@ def agentscore_gate( from flask import g, jsonify from flask import request as flask_request - client = GateClient( + client = AgentScoreCore( api_key=api_key, require_kyc=require_kyc, require_sanctions_clear=require_sanctions_clear, diff --git a/agentscore_commerce/identity/middleware.py b/agentscore_commerce/identity/middleware.py index 18f57dd..2f41cc2 100644 --- a/agentscore_commerce/identity/middleware.py +++ b/agentscore_commerce/identity/middleware.py @@ -21,8 +21,8 @@ build_missing_identity_reason, denial_reason_to_body, ) -from agentscore_commerce.identity.client import ( - GateClient, +from agentscore_commerce.identity.core import ( + AgentScoreCore, InvalidCredentialError, PaymentRequiredError, QuotaExceededError, @@ -165,7 +165,7 @@ def __init__( create_session_on_missing: CreateSessionOnMissing | None = None, ) -> None: self.app = app - self._client = GateClient( + self._client = AgentScoreCore( api_key=api_key, require_kyc=require_kyc, require_sanctions_clear=require_sanctions_clear, diff --git a/agentscore_commerce/identity/policy.py b/agentscore_commerce/identity/policy.py index fd9c8b0..ce042c2 100644 --- a/agentscore_commerce/identity/policy.py +++ b/agentscore_commerce/identity/policy.py @@ -90,7 +90,7 @@ def build_gate_from_policy( Use a fresh gate per request rather than constructing once at module scope when policy varies per resource (e.g. per product). The gate is cheap to - instantiate; AgentScore's response cache lives on :class:`GateClient` + instantiate; AgentScore's response cache lives on :class:`AgentScoreCore` inside the gate, scoped to the lifetime of this gate instance. """ if policy is None: diff --git a/agentscore_commerce/identity/sanic.py b/agentscore_commerce/identity/sanic.py index d08a186..f43ed7a 100644 --- a/agentscore_commerce/identity/sanic.py +++ b/agentscore_commerce/identity/sanic.py @@ -19,8 +19,8 @@ build_missing_identity_reason, denial_reason_to_body, ) -from agentscore_commerce.identity.client import ( - GateClient, +from agentscore_commerce.identity.core import ( + AgentScoreCore, InvalidCredentialError, PaymentRequiredError, QuotaExceededError, @@ -164,7 +164,7 @@ def agentscore_gate( """ from sanic import response - client = GateClient( + client = AgentScoreCore( api_key=api_key, require_kyc=require_kyc, require_sanctions_clear=require_sanctions_clear, diff --git a/agentscore_commerce/identity/signer.py b/agentscore_commerce/identity/signer.py index 223dbe1..3e7b5ac 100644 --- a/agentscore_commerce/identity/signer.py +++ b/agentscore_commerce/identity/signer.py @@ -8,7 +8,7 @@ (``Authorization: Payment``), not x402, so they don't arrive at this helper. If a non-AgentScore merchant does receive a legacy x402 SVM payload, this function returns ``None``; custom adapters that recover the Solana signer themselves should pass -``signer={address, network}`` directly to ``GateClient.check``/``acheck``. +``signer={address, network}`` directly to ``AgentScoreCore.check``/``acheck``. Tempo MPP signer extraction is also caller-supplied; there's no pip-installable equivalent of the node ``mppx`` library today. diff --git a/agentscore_commerce/identity/types.py b/agentscore_commerce/identity/types.py index f9fad6d..33a0e23 100644 --- a/agentscore_commerce/identity/types.py +++ b/agentscore_commerce/identity/types.py @@ -122,7 +122,7 @@ class VerifyWalletSignerResult: @dataclass class SignerVerdict: - """Combined wallet-signer verdict surfaced by :meth:`GateClient.get_signer_verdict`. + """Combined wallet-signer verdict surfaced by :meth:`AgentScoreCore.get_signer_verdict`. Both ``signer_match`` and ``signer_sanctions`` come through the gate's primary ``/v1/assess`` call (single round trip). ``signer_match`` describes the wallet- diff --git a/examples/README.md b/examples/README.md index 14be31f..fd27e0e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -47,7 +47,7 @@ AgentScore Commerce handles the agent commerce protocol layer; everything else i Python wraps `x402[evm]` and `pympp[server,tempo,stripe]` as peer deps; `@solana/mpp` has no Python equivalent today. Two implications: -1. **`extract_payment_signer` returns EVM only.** Solana SPL Token payer recovery requires a Solana SDK (`solders` / `solana-py`) which isn't bundled. Custom adapters that wire Solana signer recovery should pass `signer={address, network}` directly to `GateClient.acheck()`; the API returns the wallet-binding + sanctions verdicts on the same response. +1. **`extract_payment_signer` returns EVM only.** Solana SPL Token payer recovery requires a Solana SDK (`solders` / `solana-py`) which isn't bundled. Custom adapters that wire Solana signer recovery should pass `signer={address, network}` directly to `AgentScoreCore.acheck()`; the API returns the wallet-binding + sanctions verdicts on the same response. 2. **Streaming session payments (variable_cost_merchant.py)** sketches the protocol but doesn't ship a working tempo session implementation; there's no pip-installable `mppx` equivalent. The example shows the response shape; vendors using session payments today should check the [tempo session protocol docs](https://mpp.dev/guides/streamed-payments) and bind to a Solana wallet library directly. For Python merchants on x402 alone (Base or Solana), every helper (`create_x402_server`, `create_mppx_server`, directives, headers, dispatch, settle-overrides, signer extraction for EVM, accepted_methods, agent_instructions, how_to_pay) is fully native. diff --git a/tests/test_aiohttp.py b/tests/test_aiohttp.py index c299a45..de6d201 100644 --- a/tests/test_aiohttp.py +++ b/tests/test_aiohttp.py @@ -236,7 +236,7 @@ async def _snoop(request: web.Request) -> web.Response: return web.json_response({k: v for k, v in state.items() if k != "client"}) with patch( - "agentscore_commerce.identity.aiohttp.GateClient.acheck_identity", + "agentscore_commerce.identity.aiohttp.AgentScoreCore.acheck_identity", side_effect=httpx.TimeoutException("read timeout"), ): client = await _client(_make_app(handler=_snoop, fail_open=True)) @@ -254,7 +254,7 @@ async def _snoop(request: web.Request) -> web.Response: return web.json_response({k: v for k, v in state.items() if k != "client"}) with patch( - "agentscore_commerce.identity.aiohttp.GateClient.acheck_identity", + "agentscore_commerce.identity.aiohttp.AgentScoreCore.acheck_identity", side_effect=RuntimeError("oops"), ): client = await _client(_make_app(handler=_snoop, fail_open=True)) @@ -431,7 +431,7 @@ async def test_no_ops_when_gate_did_not_run(self): # Handler wired without the gate middleware — capture_wallet must silently no-op. app = web.Application() app.router.add_post("/", _capture_handler) - with patch("agentscore_commerce.identity.client.GateClient.acapture_wallet", new=AsyncMock()) as mock_cap: + with patch("agentscore_commerce.identity.core.AgentScoreCore.acapture_wallet", new=AsyncMock()) as mock_cap: client = await _client(app) async with client: resp = await client.post("/") diff --git a/tests/test_client.py b/tests/test_core.py similarity index 96% rename from tests/test_client.py rename to tests/test_core.py index 2a50874..466f099 100644 --- a/tests/test_client.py +++ b/tests/test_core.py @@ -1,4 +1,4 @@ -"""Direct unit tests for GateClient internals.""" +"""Direct unit tests for AgentScoreCore internals.""" from __future__ import annotations @@ -9,13 +9,13 @@ import pytest import respx -from agentscore_commerce.identity.client import GateClient, PaymentRequiredError +from agentscore_commerce.identity.core import AgentScoreCore, PaymentRequiredError -def _make_client(**kwargs) -> GateClient: +def _make_client(**kwargs) -> AgentScoreCore: defaults = {"api_key": "ask_test_key"} defaults.update(kwargs) - return GateClient(**defaults) + return AgentScoreCore(**defaults) class TestHeaders: @@ -195,7 +195,7 @@ class TestParseResponseStatusCodes: """ def test_429_raises_quota_exceeded(self): - from agentscore_commerce.identity.client import QuotaExceededError + from agentscore_commerce.identity.core import QuotaExceededError client = _make_client() resp = MagicMock(spec=httpx.Response) @@ -204,7 +204,7 @@ def test_429_raises_quota_exceeded(self): client._parse_response(resp) def test_401_token_expired_raises_token_denied(self): - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError client = _make_client() resp = MagicMock(spec=httpx.Response) @@ -220,7 +220,7 @@ def test_401_token_expired_raises_token_denied(self): assert info.value.body.get("verify_url") == "https://x" def test_401_invalid_credential_raises_invalid_credential(self): - from agentscore_commerce.identity.client import InvalidCredentialError + from agentscore_commerce.identity.core import InvalidCredentialError client = _make_client() resp = MagicMock(spec=httpx.Response) @@ -342,7 +342,7 @@ def test_check_raises_on_api_error(self): def test_check_raises_quota_exceeded_on_429(self): """429 must be distinguishable from generic 5xx so adapters surface ``infra_reason='quota_exceeded'`` separately when fail_open=True.""" - from agentscore_commerce.identity.client import QuotaExceededError + from agentscore_commerce.identity.core import QuotaExceededError client = _make_client(fail_open=False) respx.post(ASSESS_URL).mock(return_value=httpx.Response(429)) @@ -355,7 +355,7 @@ def test_check_raises_quota_exceeded_on_typed_429(self): """SDK emits typed QuotaExceededError when body has error.code='quota_exceeded' — commerce wraps it so callers get the gate's QuotaExceededError sentinel. """ - from agentscore_commerce.identity.client import QuotaExceededError + from agentscore_commerce.identity.core import QuotaExceededError client = _make_client(fail_open=False) respx.post(ASSESS_URL).mock( @@ -380,7 +380,7 @@ def test_check_raises_payment_required_on_402(self): @respx.mock def test_check_raises_token_denied_on_typed_401(self): """401 with error.code='token_expired' surfaces TokenDeniedError carrying body.""" - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError client = _make_client(fail_open=False) respx.post(ASSESS_URL).mock( @@ -402,7 +402,7 @@ def test_check_raises_token_denied_on_typed_401(self): @respx.mock def test_check_raises_invalid_credential_on_typed_401(self): """401 with error.code='invalid_credential' surfaces InvalidCredentialError.""" - from agentscore_commerce.identity.client import InvalidCredentialError + from agentscore_commerce.identity.core import InvalidCredentialError client = _make_client(fail_open=False) respx.post(ASSESS_URL).mock( @@ -734,7 +734,7 @@ class TestInvalidCredential: @respx.mock def test_raises_invalid_credential_on_401_invalid_credential(self): - from agentscore_commerce.identity.client import InvalidCredentialError + from agentscore_commerce.identity.core import InvalidCredentialError respx.post(ASSESS_URL).mock( return_value=httpx.Response( @@ -768,7 +768,7 @@ def test_logs_when_401_body_isnt_valid_json(self): client.check(operator_token="opc_x") def test_build_invalid_credential_reason_carries_action_copy(self): - from agentscore_commerce.identity.client import build_invalid_credential_reason + from agentscore_commerce.identity.core import build_invalid_credential_reason reason = build_invalid_credential_reason() assert reason.code == "invalid_credential" @@ -790,7 +790,7 @@ class TestAcheckTypedErrors: @pytest.mark.asyncio @respx.mock async def test_acheck_raises_quota_exceeded_on_typed_429(self): - from agentscore_commerce.identity.client import QuotaExceededError + from agentscore_commerce.identity.core import QuotaExceededError client = _make_client() respx.post(ASSESS_URL).mock( @@ -807,7 +807,7 @@ async def test_acheck_raises_quota_exceeded_on_typed_429(self): @respx.mock async def test_acheck_raises_quota_exceeded_on_untyped_429(self): """Mirrors the sync defensive 429-fallback path.""" - from agentscore_commerce.identity.client import QuotaExceededError + from agentscore_commerce.identity.core import QuotaExceededError client = _make_client() respx.post(ASSESS_URL).mock(return_value=httpx.Response(429)) @@ -827,7 +827,7 @@ async def test_acheck_raises_payment_required_on_402(self): @pytest.mark.asyncio @respx.mock async def test_acheck_raises_token_denied_on_typed_401(self): - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError client = _make_client() respx.post(ASSESS_URL).mock( @@ -849,7 +849,7 @@ async def test_acheck_raises_token_denied_on_typed_401(self): @pytest.mark.asyncio @respx.mock async def test_acheck_raises_invalid_credential_on_typed_401(self): - from agentscore_commerce.identity.client import InvalidCredentialError + from agentscore_commerce.identity.core import InvalidCredentialError client = _make_client() respx.post(ASSESS_URL).mock( diff --git a/tests/test_django.py b/tests/test_django.py index 34adb12..746ede1 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -22,7 +22,7 @@ from django.http import HttpRequest, JsonResponse from django.test import RequestFactory -from agentscore_commerce.identity.client import PaymentRequiredError, QuotaExceededError +from agentscore_commerce.identity.core import PaymentRequiredError, QuotaExceededError from agentscore_commerce.identity.django import AgentScoreMiddleware, get_agentscore_data from agentscore_commerce.identity.types import AssessResult @@ -54,7 +54,7 @@ def _make_middleware(self, **config_overrides: object) -> AgentScoreMiddleware: def test_allows_trusted_wallet(self) -> None: mw = self._make_middleware() request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=_mock_result()): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=_mock_result()): resp = mw(request) assert resp.status_code == 200 data = json.loads(resp.content) @@ -64,7 +64,7 @@ def test_blocks_untrusted_wallet(self) -> None: mw = self._make_middleware() result = AssessResult(allow=False, decision="deny", reasons=["kyc_required"], raw={}) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=result): resp = mw(request) assert resp.status_code == 403 data = json.loads(resp.content) @@ -87,14 +87,14 @@ def test_missing_wallet_fail_open(self) -> None: def test_api_error_fail_open(self) -> None: mw = self._make_middleware(fail_open=True) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", side_effect=RuntimeError("timeout")): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", side_effect=RuntimeError("timeout")): resp = mw(request) assert resp.status_code == 200 def test_api_error_fail_closed(self) -> None: mw = self._make_middleware() request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", side_effect=RuntimeError("timeout")): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", side_effect=RuntimeError("timeout")): resp = mw(request) assert resp.status_code == 503 data = json.loads(resp.content) @@ -105,7 +105,7 @@ def test_get_gate_degraded_state_returns_default_for_normal_allow(self) -> None: mw = self._make_middleware() request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=_mock_result()): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=_mock_result()): mw(request) assert get_gate_degraded_state(request) == {"degraded": False} @@ -115,7 +115,7 @@ def test_get_gate_degraded_state_returns_infra_reason_when_degraded(self) -> Non mw = self._make_middleware(fail_open=True) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") with patch( - "agentscore_commerce.identity.django.GateClient.check", + "agentscore_commerce.identity.django.AgentScoreCore.check", side_effect=QuotaExceededError("quota_exceeded"), ): mw(request) @@ -125,7 +125,7 @@ def test_quota_exceeded_fail_open_marks_degraded(self) -> None: mw = self._make_middleware(fail_open=True) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") with patch( - "agentscore_commerce.identity.django.GateClient.check", + "agentscore_commerce.identity.django.AgentScoreCore.check", side_effect=QuotaExceededError("quota_exceeded"), ): resp = mw(request) @@ -138,7 +138,7 @@ def test_quota_exceeded_fail_closed_returns_api_error(self) -> None: mw = self._make_middleware() request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") with patch( - "agentscore_commerce.identity.django.GateClient.check", + "agentscore_commerce.identity.django.AgentScoreCore.check", side_effect=QuotaExceededError("quota_exceeded"), ): resp = mw(request) @@ -153,7 +153,7 @@ def test_timeout_fail_open_marks_degraded_with_network_timeout(self) -> None: mw = self._make_middleware(fail_open=True) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") with patch( - "agentscore_commerce.identity.django.GateClient.check", + "agentscore_commerce.identity.django.AgentScoreCore.check", side_effect=httpx.TimeoutException("read timeout"), ): resp = mw(request) @@ -166,7 +166,7 @@ def test_generic_exception_fail_open_marks_degraded_with_api_error(self) -> None mw = self._make_middleware(fail_open=True) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") with patch( - "agentscore_commerce.identity.django.GateClient.check", + "agentscore_commerce.identity.django.AgentScoreCore.check", side_effect=RuntimeError("oops"), ): resp = mw(request) @@ -178,14 +178,14 @@ def test_generic_exception_fail_open_marks_degraded_with_api_error(self) -> None def test_payment_required_fail_open(self) -> None: mw = self._make_middleware(fail_open=True) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", side_effect=PaymentRequiredError): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", side_effect=PaymentRequiredError): resp = mw(request) assert resp.status_code == 200 def test_payment_required_fail_closed(self) -> None: mw = self._make_middleware() request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", side_effect=PaymentRequiredError): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", side_effect=PaymentRequiredError): resp = mw(request) assert resp.status_code == 403 data = json.loads(resp.content) @@ -198,7 +198,7 @@ def custom_extract_chain(_request): mw = self._make_middleware(extract_chain=custom_extract_chain) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") with patch( - "agentscore_commerce.identity.django.GateClient.check_identity", return_value=_mock_result() + "agentscore_commerce.identity.django.AgentScoreCore.check_identity", return_value=_mock_result() ) as mock_check: mw(request) call_args = mock_check.call_args @@ -209,14 +209,14 @@ def test_null_decision_allows_request(self) -> None: mw = self._make_middleware() request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") result = AssessResult(allow=True, decision=None, reasons=[], raw={"score": 75}) - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=result): resp = mw(request) assert resp.status_code == 200 def test_attaches_data_to_request(self) -> None: mw = self._make_middleware() request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=_mock_result()): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=_mock_result()): mw(request) assert hasattr(request, "agentscore") assert request.agentscore["score"] == 80 # type: ignore[attr-defined] @@ -224,7 +224,7 @@ def test_attaches_data_to_request(self) -> None: def test_get_agentscore_data_returns_assess_after_pass(self) -> None: mw = self._make_middleware() request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=_mock_result()): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=_mock_result()): mw(request) assert get_agentscore_data(request) == {"score": 80, "grade": "B"} @@ -233,7 +233,7 @@ def test_get_agentscore_data_returns_none_for_ungated_request(self) -> None: assert get_agentscore_data(request) is None def test_compliance_params_passed_to_client(self) -> None: - with patch("agentscore_commerce.identity.django.GateClient") as mock_cls: + with patch("agentscore_commerce.identity.django.AgentScoreCore") as mock_cls: mock_cls.return_value = mock_cls mock_cls.fail_open = False mock_cls.check.return_value = _mock_result() @@ -261,7 +261,7 @@ def test_deny_includes_reasons_from_compliance(self) -> None: }, ) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=result): resp = mw(request) assert resp.status_code == 403 data = json.loads(resp.content) @@ -282,7 +282,7 @@ def test_allow_with_operator_verification_attaches_to_request(self) -> None: } result = AssessResult(allow=True, decision="allow", reasons=[], raw=raw) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=result): resp = mw(request) assert resp.status_code == 200 assert request.agentscore["operator_verification"]["level"] == "kyc_verified" # type: ignore[attr-defined] @@ -295,7 +295,7 @@ def test_verify_url_available_in_raw_on_deny(self) -> None: } result = AssessResult(allow=False, decision="deny", reasons=["kyc_required"], raw=raw) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=result): resp = mw(request) assert resp.status_code == 403 data = json.loads(resp.content) @@ -376,7 +376,7 @@ def test_fixable_wallet_denial_bootstraps_session(self) -> None: request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") with ( patch( - "agentscore_commerce.identity.django.GateClient.check", + "agentscore_commerce.identity.django.AgentScoreCore.check", return_value=result, ), patch( @@ -400,7 +400,7 @@ def test_unfixable_wallet_denial_returns_bare_wallet_not_trusted(self) -> None: request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") with ( patch( - "agentscore_commerce.identity.django.GateClient.check", + "agentscore_commerce.identity.django.AgentScoreCore.check", return_value=result, ), patch( @@ -463,7 +463,7 @@ def test_operator_token_header_calls_check_identity(self) -> None: mw = self._make_middleware() request = self.factory.get("/", HTTP_X_OPERATOR_TOKEN="opc_django_test") with patch( - "agentscore_commerce.identity.django.GateClient.check_identity", return_value=_mock_result() + "agentscore_commerce.identity.django.AgentScoreCore.check_identity", return_value=_mock_result() ) as mock_check: resp = mw(request) assert resp.status_code == 200 @@ -484,8 +484,8 @@ def test_captures_when_operator_token_present(self) -> None: mw = self._make_middleware() request = self.factory.post("/purchase", HTTP_X_OPERATOR_TOKEN="opc_django_cap") with ( - patch("agentscore_commerce.identity.django.GateClient.check", return_value=_mock_result()), - patch("agentscore_commerce.identity.django.GateClient.capture_wallet") as mock_capture, + patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=_mock_result()), + patch("agentscore_commerce.identity.django.AgentScoreCore.capture_wallet") as mock_capture, ): mw(request) capture_wallet(request, "0xsigner", "evm", idempotency_key="pi_abc") @@ -502,8 +502,8 @@ def test_no_ops_when_wallet_authenticated(self) -> None: mw = self._make_middleware() request = self.factory.post("/purchase", HTTP_X_WALLET_ADDRESS="0xabc") with ( - patch("agentscore_commerce.identity.django.GateClient.check", return_value=_mock_result()), - patch("agentscore_commerce.identity.django.GateClient.capture_wallet") as mock_capture, + patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=_mock_result()), + patch("agentscore_commerce.identity.django.AgentScoreCore.capture_wallet") as mock_capture, ): mw(request) capture_wallet(request, "0xsigner", "evm") @@ -514,7 +514,7 @@ def test_no_ops_when_gate_did_not_run(self) -> None: # A handler calling capture_wallet without the gate middleware ever running. request = self.factory.post("/purchase") - with patch("agentscore_commerce.identity.django.GateClient.capture_wallet") as mock_capture: + with patch("agentscore_commerce.identity.django.AgentScoreCore.capture_wallet") as mock_capture: capture_wallet(request, "0xsigner", "evm") mock_capture.assert_not_called() @@ -608,7 +608,7 @@ def boom_view(_request: HttpRequest) -> JsonResponse: settings.AGENTSCORE_GATE = {"api_key": "test-key", "fail_open": True} mw = AgentScoreMiddleware(boom_view) - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=_mock_result()): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=_mock_result()): request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") try: mw(request) @@ -647,7 +647,7 @@ def view(request: HttpRequest) -> JsonResponse: quota=GateQuotaInfo(limit=1500, used=1200, reset="2026-06-01T00:00:00Z"), ) request = self.factory.get("/", HTTP_X_WALLET_ADDRESS="0xabc") - with patch("agentscore_commerce.identity.django.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.django.AgentScoreCore.check", return_value=result): resp = mw(request) assert resp.status_code == 200 assert captured["quota"] is not None diff --git a/tests/test_fastapi.py b/tests/test_fastapi.py index 1c96497..12940e9 100644 --- a/tests/test_fastapi.py +++ b/tests/test_fastapi.py @@ -191,7 +191,7 @@ def _root(req: Request): return {"ok": True} with patch( - "agentscore_commerce.identity.fastapi.GateClient.acheck_identity", + "agentscore_commerce.identity.fastapi.AgentScoreCore.acheck_identity", new=AsyncMock( return_value=__import__("agentscore_commerce.identity.types", fromlist=["AssessResult"]).AssessResult( allow=True, decision="allow" @@ -207,7 +207,7 @@ def test_get_gate_degraded_state_returns_infra_reason_when_degraded(self): """get_gate_degraded_state returns {degraded: True, infra_reason: ...} when gate degraded.""" from fastapi import FastAPI - from agentscore_commerce.identity.client import QuotaExceededError + from agentscore_commerce.identity.core import QuotaExceededError from agentscore_commerce.identity.fastapi import get_gate_degraded_state gate = AgentScoreGate(api_key="ask_test", fail_open=True) @@ -220,7 +220,7 @@ def _root(req: Request): return {"ok": True} with patch( - "agentscore_commerce.identity.fastapi.GateClient.acheck_identity", + "agentscore_commerce.identity.fastapi.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=QuotaExceededError("quota_exceeded")), ): client = TestClient(app) @@ -246,7 +246,7 @@ def _root(req: Request): return {"ok": True} with patch( - "agentscore_commerce.identity.fastapi.GateClient.acheck_identity", + "agentscore_commerce.identity.fastapi.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=httpx.TimeoutException("read timeout")), ): client = TestClient(app) @@ -455,7 +455,7 @@ async def purchase(request: Request): client = TestClient(app) with patch( - "agentscore_commerce.identity.client.GateClient.acapture_wallet", + "agentscore_commerce.identity.core.AgentScoreCore.acapture_wallet", new=AsyncMock(), ) as mock_cap: resp = client.post("/purchase") diff --git a/tests/test_flask.py b/tests/test_flask.py index 22270a8..1500924 100644 --- a/tests/test_flask.py +++ b/tests/test_flask.py @@ -8,7 +8,7 @@ import pytest from flask import Flask -from agentscore_commerce.identity.client import PaymentRequiredError, QuotaExceededError +from agentscore_commerce.identity.core import PaymentRequiredError, QuotaExceededError from agentscore_commerce.identity.flask import agentscore_gate, get_agentscore_data from agentscore_commerce.identity.types import AssessResult @@ -36,7 +36,7 @@ class TestFlaskGate: def test_allows_trusted_wallet(self) -> None: app = _make_app() - with patch("agentscore_commerce.identity.flask.GateClient.check", return_value=_mock_result()): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=_mock_result()): client = app.test_client() resp = client.get("/", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 200 @@ -53,7 +53,7 @@ def test_get_agentscore_data_returns_assess_after_pass(self) -> None: def index() -> dict[str, object]: return {"assess": get_agentscore_data()} - with patch("agentscore_commerce.identity.flask.GateClient.check", return_value=_mock_result()): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=_mock_result()): resp = app.test_client().get("/", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 200 assert resp.get_json()["assess"] == {"score": 80, "grade": "B"} @@ -66,7 +66,7 @@ def test_get_agentscore_data_returns_none_outside_request(self) -> None: def test_blocks_untrusted_wallet(self) -> None: app = _make_app() result = AssessResult(allow=False, decision="deny", reasons=["kyc_required"], raw={}) - with patch("agentscore_commerce.identity.flask.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=result): client = app.test_client() resp = client.get("/", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 403 @@ -89,14 +89,14 @@ def test_missing_wallet_fail_open(self) -> None: def test_api_error_fail_open(self) -> None: app = _make_app(fail_open=True) - with patch("agentscore_commerce.identity.flask.GateClient.check", side_effect=RuntimeError("timeout")): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=RuntimeError("timeout")): client = app.test_client() resp = client.get("/", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 200 def test_api_error_fail_closed(self) -> None: app = _make_app() - with patch("agentscore_commerce.identity.flask.GateClient.check", side_effect=RuntimeError("timeout")): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=RuntimeError("timeout")): client = app.test_client() resp = client.get("/", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 503 @@ -114,7 +114,7 @@ def _snoop(): captured.update(get_gate_degraded_state()) return {"ok": True} - with patch("agentscore_commerce.identity.flask.GateClient.check", return_value=_mock_result()): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=_mock_result()): resp = app.test_client().get("/snoop", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 200 assert captured == {"degraded": False} @@ -131,7 +131,7 @@ def _snoop(): return {"ok": True} with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=QuotaExceededError("quota_exceeded"), ): resp = app.test_client().get("/snoop", headers={"x-wallet-address": "0xabc"}) @@ -151,7 +151,7 @@ def _snoop(): return jsonify({k: v for k, v in state.items() if k != "client"}) with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=QuotaExceededError("quota_exceeded"), ): client = app.test_client() @@ -166,7 +166,7 @@ def test_quota_exceeded_fail_closed_returns_api_error(self) -> None: app = _make_app() with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=QuotaExceededError("quota_exceeded"), ): client = app.test_client() @@ -189,7 +189,7 @@ def _snoop(): return jsonify({k: v for k, v in state.items() if k != "client"}) with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=httpx.TimeoutException("read timeout"), ): client = app.test_client() @@ -210,7 +210,7 @@ def _snoop(): return jsonify({k: v for k, v in state.items() if k != "client"}) with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=RuntimeError("oops"), ): client = app.test_client() @@ -223,7 +223,7 @@ def _snoop(): def test_payment_required_fail_open(self) -> None: app = _make_app(fail_open=True) with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=PaymentRequiredError, ): client = app.test_client() @@ -233,7 +233,7 @@ def test_payment_required_fail_open(self) -> None: def test_payment_required_fail_closed(self) -> None: app = _make_app() with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=PaymentRequiredError, ): client = app.test_client() @@ -248,7 +248,7 @@ def custom_extract_chain(_request): app = _make_app(extract_chain=custom_extract_chain) with patch( - "agentscore_commerce.identity.flask.GateClient.check_identity", return_value=_mock_result() + "agentscore_commerce.identity.flask.AgentScoreCore.check_identity", return_value=_mock_result() ) as mock_check: client = app.test_client() client.get("/", headers={"x-wallet-address": "0xabc"}) @@ -271,7 +271,7 @@ def test_requires_api_key(self) -> None: agentscore_gate(app, api_key="") def test_compliance_params_passed_to_client(self) -> None: - with patch("agentscore_commerce.identity.flask.GateClient") as mock_cls: + with patch("agentscore_commerce.identity.flask.AgentScoreCore") as mock_cls: mock_cls.return_value = mock_cls mock_cls.fail_open = False app = Flask(__name__) @@ -300,7 +300,7 @@ def test_deny_includes_compliance_reasons(self) -> None: "operator_verification": {"level": "none"}, }, ) - with patch("agentscore_commerce.identity.flask.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=result): client = app.test_client() resp = client.get("/", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 403 @@ -321,7 +321,7 @@ def test_allow_with_operator_verification_attaches_to_g(self) -> None: }, } result = AssessResult(allow=True, decision="allow", reasons=[], raw=raw) - with patch("agentscore_commerce.identity.flask.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=result): client = app.test_client() resp = client.get("/", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 200 @@ -335,7 +335,7 @@ def test_verify_url_available_in_raw_on_deny(self) -> None: "verify_url": "https://agentscore.sh/verify/abc123", } result = AssessResult(allow=False, decision="deny", reasons=["kyc_required"], raw=raw) - with patch("agentscore_commerce.identity.flask.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=result): client = app.test_client() resp = client.get("/", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 403 @@ -400,7 +400,7 @@ def test_fixable_wallet_denial_bootstraps_session(self) -> None: ) with ( patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=result, ), patch( @@ -422,7 +422,7 @@ def test_unfixable_wallet_denial_returns_bare_wallet_not_trusted(self) -> None: result = AssessResult(allow=False, decision="deny", reasons=["sanctions_flagged"], raw={}) with ( patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=result, ), patch( @@ -488,7 +488,7 @@ def test_missing_identity_fail_open(self) -> None: def test_operator_token_header_calls_check_identity(self) -> None: app = _make_app() with patch( - "agentscore_commerce.identity.flask.GateClient.check_identity", return_value=_mock_result() + "agentscore_commerce.identity.flask.AgentScoreCore.check_identity", return_value=_mock_result() ) as mock_check: client = app.test_client() resp = client.get("/", headers={"x-operator-token": "opc_flask_test"}) @@ -519,8 +519,8 @@ class TestFlaskCaptureWallet: def test_captures_when_operator_token_present(self) -> None: app = _make_capture_app() with ( - patch("agentscore_commerce.identity.flask.GateClient.check", return_value=_mock_result()), - patch("agentscore_commerce.identity.flask.GateClient.capture_wallet") as mock_capture, + patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=_mock_result()), + patch("agentscore_commerce.identity.flask.AgentScoreCore.capture_wallet") as mock_capture, ): client = app.test_client() resp = client.post("/purchase", headers={"x-operator-token": "opc_abc"}) @@ -535,8 +535,8 @@ def test_captures_when_operator_token_present(self) -> None: def test_no_ops_when_wallet_authenticated(self) -> None: app = _make_capture_app() with ( - patch("agentscore_commerce.identity.flask.GateClient.check", return_value=_mock_result()), - patch("agentscore_commerce.identity.flask.GateClient.capture_wallet") as mock_capture, + patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=_mock_result()), + patch("agentscore_commerce.identity.flask.AgentScoreCore.capture_wallet") as mock_capture, ): client = app.test_client() resp = client.post("/purchase", headers={"x-wallet-address": "0xabc"}) @@ -555,7 +555,7 @@ def test_no_ops_outside_request_context(self) -> None: # App context but no request context — Flask's `g` is only meaningful inside a request. with ( app.app_context(), - patch("agentscore_commerce.identity.flask.GateClient.capture_wallet") as mock_capture, + patch("agentscore_commerce.identity.flask.AgentScoreCore.capture_wallet") as mock_capture, ): capture_wallet("0xsigner", "evm") mock_capture.assert_not_called() @@ -623,11 +623,11 @@ class TestFlaskTokenDenied: def test_passes_through_token_expired_with_auto_session(self) -> None: # Revoked and expired credentials both surface as token_expired; adapter forwards # the API's auto-minted session fields into the 403 body. - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError app = _make_app() with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=TokenDeniedError( { "error": {"code": "token_expired", "message": "invalid"}, @@ -651,11 +651,11 @@ def test_passes_through_token_expired_with_auto_session(self) -> None: assert _json.loads(body["agent_instructions"]) == {"action": "deliver_verify_url_and_poll"} def test_passes_through_token_expired_without_next_steps(self) -> None: - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError app = _make_app() with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=TokenDeniedError({"error": {"code": "token_expired", "message": "invalid"}}), ): client = app.test_client() @@ -679,7 +679,7 @@ def test_api_error_on_connect_failure(self) -> None: app = _make_app() with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=httpx.ConnectError("dns lookup failed"), ): client = app.test_client() @@ -693,7 +693,7 @@ def test_fail_open_lets_request_through_on_unexpected_exception(self) -> None: app = _make_app(fail_open=True) with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=httpx.ConnectError("dns lookup failed"), ): client = app.test_client() @@ -705,7 +705,7 @@ def test_fail_open_lets_request_through_on_unexpected_exception(self) -> None: def test_payment_required_surfaces_as_denial(self) -> None: app = _make_app() with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=PaymentRequiredError, ): client = app.test_client() @@ -729,7 +729,7 @@ def test_missing_identity_branch_bad_on_denied_shape(self) -> None: def test_wallet_not_trusted_branch_bad_on_denied_shape(self) -> None: app = _make_app(on_denied=lambda _req, _reason: None) with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=_mock_result(allow=False, decision="deny"), ): client = app.test_client() @@ -737,11 +737,11 @@ def test_wallet_not_trusted_branch_bad_on_denied_shape(self) -> None: client.get("/", headers={"x-wallet-address": "0xabc"}) def test_token_denied_branch_bad_on_denied_shape(self) -> None: - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError app = _make_app(on_denied=lambda _req, _reason: 42) with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=TokenDeniedError({"error": {"code": "token_expired"}}), ): client = app.test_client() @@ -753,7 +753,7 @@ def test_api_error_branch_bad_on_denied_shape(self) -> None: app = _make_app(on_denied=lambda _req, _reason: ({"x": 1},)) # single-element tuple with patch( - "agentscore_commerce.identity.flask.GateClient.check", + "agentscore_commerce.identity.flask.AgentScoreCore.check", side_effect=httpx.ConnectError("dns down"), ): client = app.test_client() @@ -822,7 +822,7 @@ def quota_route(): raw={"decision": "allow"}, quota=GateQuotaInfo(limit=1500, used=1200, reset="2026-06-01T00:00:00Z"), ) - with patch("agentscore_commerce.identity.flask.GateClient.check", return_value=result): + with patch("agentscore_commerce.identity.flask.AgentScoreCore.check", return_value=result): client = app.test_client() resp = client.get("/quota", headers={"x-wallet-address": "0xabc"}) assert resp.status_code == 200 diff --git a/tests/test_get_signer_verdict.py b/tests/test_get_signer_verdict.py index 4bd566a..7572888 100644 --- a/tests/test_get_signer_verdict.py +++ b/tests/test_get_signer_verdict.py @@ -207,7 +207,7 @@ def test_sanic_get_signer_verdict_delegates_to_client() -> None: # --------------------------------------------------------------------------- -# GateClient.get_signer_verdict — projection branches +# AgentScoreCore.get_signer_verdict — projection branches # --------------------------------------------------------------------------- @@ -222,9 +222,9 @@ def test_client_get_signer_verdict_projects_each_kind(kind: str, expected_kind: """Cover the branches in _project_signer_match (pass + wallet_auth_requires_wallet_signing).""" from unittest.mock import patch - from agentscore_commerce.identity.client import GateClient + from agentscore_commerce.identity.core import AgentScoreCore - client = GateClient(api_key="test-api-key") + client = AgentScoreCore(api_key="test-api-key") def fake_post(*_args: object, **_kwargs: object) -> MagicMock: resp = MagicMock() diff --git a/tests/test_middleware.py b/tests/test_middleware.py index a9f888f..b69ab6c 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -464,7 +464,7 @@ def _snoop(request: Request) -> JSONResponse: ) with patch( - "agentscore_commerce.identity.middleware.GateClient.acheck_identity", + "agentscore_commerce.identity.middleware.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=httpx.TimeoutException("read timeout")), ): client = TestClient(app, raise_server_exceptions=False) diff --git a/tests/test_sanic.py b/tests/test_sanic.py index df6acd6..a541ff0 100644 --- a/tests/test_sanic.py +++ b/tests/test_sanic.py @@ -1,7 +1,7 @@ """Tests for the Sanic adapter. Sanic's test client runs the app on a real loopback socket and uses httpx to hit it, -which makes respx-based URL mocking awkward. We mock ``GateClient.acheck_identity`` +which makes respx-based URL mocking awkward. We mock ``AgentScoreCore.acheck_identity`` directly (matching the Flask/Django test pattern) and verify the adapter plumbing. """ @@ -46,7 +46,7 @@ class TestIdentityExtraction: def test_allows_trusted_wallet(self): app = _make_app("sanic_allow_wallet") with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(return_value=_allow_result()), ): _, resp = app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) @@ -62,7 +62,7 @@ async def handler(request): return response.json({"assess": get_agentscore_data(request)}) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(return_value=_allow_result()), ): _, resp = app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) @@ -72,7 +72,7 @@ async def handler(request): def test_denies_untrusted_wallet(self): app = _make_app("sanic_deny_wallet") with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(return_value=_deny_result()), ): _, resp = app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) @@ -94,7 +94,7 @@ def test_fail_open_allows_through_when_identity_missing(self): def test_passes_operator_token_to_assess(self): app = _make_app("sanic_operator_token") mock = AsyncMock(return_value=_allow_result()) - with patch("agentscore_commerce.identity.sanic.GateClient.acheck_identity", new=mock): + with patch("agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=mock): app.test_client.get("/", headers={"X-Operator-Token": "opc_abc"}) # First positional arg is the AgentIdentity instance. identity_arg = mock.await_args.args[0] @@ -104,11 +104,11 @@ def test_passes_operator_token_to_assess(self): class TestErrorPaths: def test_returns_403_payment_required_on_402(self): - from agentscore_commerce.identity.client import PaymentRequiredError + from agentscore_commerce.identity.core import PaymentRequiredError app = _make_app("sanic_402") with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=PaymentRequiredError()), ): _, resp = app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) @@ -118,7 +118,7 @@ def test_returns_403_payment_required_on_402(self): def test_returns_503_api_error_on_exception(self): app = _make_app("sanic_api_error") with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=RuntimeError("boom")), ): _, resp = app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) @@ -126,11 +126,11 @@ def test_returns_503_api_error_on_exception(self): assert resp.json["error"]["code"] == "api_error" def test_fail_open_allows_through_on_402(self): - from agentscore_commerce.identity.client import PaymentRequiredError + from agentscore_commerce.identity.core import PaymentRequiredError app = _make_app("sanic_fail_open_402", fail_open=True) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=PaymentRequiredError()), ): _, resp = app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) @@ -149,7 +149,7 @@ async def _snoop(request): return response.json({"ok": True}) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(return_value=_allow_result()), ): _, resp = app.test_client.get("/snoop", headers={"X-Wallet-Address": "0xabc"}) @@ -157,7 +157,7 @@ async def _snoop(request): assert captured == {"degraded": False} def test_get_gate_degraded_state_returns_infra_reason_when_degraded(self): - from agentscore_commerce.identity.client import QuotaExceededError + from agentscore_commerce.identity.core import QuotaExceededError from agentscore_commerce.identity.sanic import get_gate_degraded_state app = Sanic.get_app("sanic_get_state_degraded", force_create=True) @@ -170,7 +170,7 @@ async def _snoop(request): return response.json({"ok": True}) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=QuotaExceededError("quota_exceeded")), ): _, resp = app.test_client.get("/snoop", headers={"X-Wallet-Address": "0xabc"}) @@ -180,11 +180,11 @@ async def _snoop(request): def test_quota_exceeded_returns_503_when_fail_closed(self): import json as _json - from agentscore_commerce.identity.client import QuotaExceededError + from agentscore_commerce.identity.core import QuotaExceededError app = _make_app("sanic_quota_closed") with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=QuotaExceededError("quota_exceeded")), ): _, resp = app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) @@ -195,7 +195,7 @@ def test_quota_exceeded_returns_503_when_fail_closed(self): assert "merchant-side issue" in instructions["steps"][0] def test_quota_exceeded_marks_degraded_when_fail_open(self): - from agentscore_commerce.identity.client import QuotaExceededError + from agentscore_commerce.identity.core import QuotaExceededError from agentscore_commerce.identity.sanic import GATE_STATE_ATTR # Build a fresh app to inspect gate state. @@ -208,7 +208,7 @@ async def _snoop(request): return response.json({k: v for k, v in state.items() if k != "client"}) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=QuotaExceededError("quota_exceeded")), ): _, resp = app.test_client.get("/snoop", headers={"X-Wallet-Address": "0xabc"}) @@ -231,7 +231,7 @@ async def _snoop(request): return response.json({k: v for k, v in state.items() if k != "client"}) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=httpx.TimeoutException("read timeout")), ): _, resp = app.test_client.get("/snoop", headers={"X-Wallet-Address": "0xabc"}) @@ -243,7 +243,7 @@ async def _snoop(request): def test_fail_open_allows_through_on_api_error(self): app = _make_app("sanic_fail_open_api", fail_open=True) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=RuntimeError("boom")), ): _, resp = app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) @@ -253,10 +253,10 @@ def test_fail_open_allows_through_on_api_error(self): class TestChainOption: def test_no_extract_chain_passes_none_to_acheck_identity(self): """Adapter passes None as chain override when extract_chain isn't configured, - so GateClient's constructor-level chain takes effect (or no chain is sent).""" + so AgentScoreCore's constructor-level chain takes effect (or no chain is sent).""" app = _make_app("sanic_chain_none", chain="solana") mock = AsyncMock(return_value=_allow_result()) - with patch("agentscore_commerce.identity.sanic.GateClient.acheck_identity", new=mock): + with patch("agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=mock): app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) chain_arg = mock.await_args.args[1] assert chain_arg is None # extract_chain not set → adapter passes None @@ -264,12 +264,12 @@ def test_no_extract_chain_passes_none_to_acheck_identity(self): def test_extract_chain_callback_passed_to_acheck_identity(self): app = _make_app("sanic_chain_callback", extract_chain=lambda _req: "ethereum") mock = AsyncMock(return_value=_allow_result()) - with patch("agentscore_commerce.identity.sanic.GateClient.acheck_identity", new=mock): + with patch("agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=mock): app.test_client.get("/", headers={"X-Wallet-Address": "0xabc"}) assert mock.await_args.args[1] == "ethereum" def test_constructor_chain_stored_on_client(self): - """The constructor-level `chain` option is forwarded to GateClient so it gets + """The constructor-level `chain` option is forwarded to AgentScoreCore so it gets embedded in every outbound /v1/assess body (verified in test_client.py).""" app = _make_app("sanic_chain_ctor", chain="base") # Access the client instance via the registered middleware to confirm chain was stored. @@ -328,7 +328,7 @@ def test_fixable_wallet_denial_bootstraps_session(self): ) with ( patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(return_value=kyc_result), ), patch( @@ -350,7 +350,7 @@ def test_unfixable_wallet_denial_returns_bare_wallet_not_trusted(self): ) with ( patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(return_value=unfixable), ), patch( @@ -369,11 +369,11 @@ def test_captures_when_operator_token_present(self): app = _make_app("sanic_capture_op") with ( patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(return_value=_allow_result()), ), patch( - "agentscore_commerce.identity.sanic.GateClient.acapture_wallet", + "agentscore_commerce.identity.sanic.AgentScoreCore.acapture_wallet", new=AsyncMock(), ) as mock_capture, ): @@ -390,11 +390,11 @@ def test_no_ops_when_wallet_authenticated(self): app = _make_app("sanic_capture_wallet") with ( patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(return_value=_allow_result()), ), patch( - "agentscore_commerce.identity.sanic.GateClient.acapture_wallet", + "agentscore_commerce.identity.sanic.AgentScoreCore.acapture_wallet", new=AsyncMock(), ) as mock_capture, ): @@ -412,7 +412,7 @@ async def purchase(request): return response.json({"ok": True}) with patch( - "agentscore_commerce.identity.sanic.GateClient.acapture_wallet", + "agentscore_commerce.identity.sanic.AgentScoreCore.acapture_wallet", new=AsyncMock(), ) as mock_capture: _, resp = app.test_client.post("/purchase") @@ -421,7 +421,7 @@ async def purchase(request): def test_sanic_passes_through_token_expired(): - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError app = Sanic("sanic_token_expired_test") agentscore_gate(app, api_key="ak", fail_open=False) @@ -431,7 +431,7 @@ async def index(_request): return response.json({"ok": True}) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock( side_effect=TokenDeniedError( { @@ -466,7 +466,7 @@ async def index(_request): return response.json({"ok": True}) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(side_effect=RuntimeError("unexpected")), ): _req, resp = app.test_client.get("/", headers={"x-wallet-address": "0xabc"}) @@ -497,7 +497,7 @@ async def index(request): quota=GateQuotaInfo(limit=1500, used=1200, reset="2026-06-01T00:00:00Z"), ) with patch( - "agentscore_commerce.identity.sanic.GateClient.acheck_identity", + "agentscore_commerce.identity.sanic.AgentScoreCore.acheck_identity", new=AsyncMock(return_value=result), ): _req, resp = app.test_client.get("/", headers={"x-wallet-address": "0xabc"}) diff --git a/tests/test_signer_match.py b/tests/test_signer_match.py index 9095a46..6cfd08a 100644 --- a/tests/test_signer_match.py +++ b/tests/test_signer_match.py @@ -16,7 +16,7 @@ from agentscore_commerce.identity import ( AgentMemoryHint, - GateClient, + AgentScoreCore, build_agent_memory_hint, extract_x402_signer, ) @@ -83,13 +83,13 @@ def test_extract_x402_signer_rejects_non_evm() -> None: # --------------------------------------------------------------------------- -# GateClient.check passes signer through; client.get_signer_verdict reads it back +# AgentScoreCore.check passes signer through; client.get_signer_verdict reads it back # --------------------------------------------------------------------------- def test_check_forwards_signer_to_assess_body() -> None: """Adapter pre-extracts the signer; client.check threads it onto the request body.""" - client = GateClient(api_key=API_KEY) + client = AgentScoreCore(api_key=API_KEY) captured: dict[str, object] = {} def fake_post(*_args: object, **kwargs: object) -> MagicMock: @@ -109,7 +109,7 @@ def fake_post(*_args: object, **kwargs: object) -> MagicMock: def test_get_signer_verdict_projects_cached_signer_match() -> None: """After a check() with signer, get_signer_verdict reads signer_match + signer_sanctions.""" - client = GateClient(api_key=API_KEY) + client = AgentScoreCore(api_key=API_KEY) def fake_post(*_args: object, **_kwargs: object) -> MagicMock: resp = MagicMock() @@ -147,7 +147,7 @@ def fake_post(*_args: object, **_kwargs: object) -> MagicMock: def test_get_signer_verdict_returns_none_when_no_signer_blocks() -> None: """Operator-token-only paths leave signer_match + signer_sanctions absent.""" - client = GateClient(api_key=API_KEY) + client = AgentScoreCore(api_key=API_KEY) def fake_post(*_args: object, **_kwargs: object) -> MagicMock: resp = MagicMock() @@ -164,7 +164,7 @@ def fake_post(*_args: object, **_kwargs: object) -> MagicMock: def test_get_signer_verdict_returns_none_when_address_not_cached() -> None: """No assess call yet → no cache entry → no verdict.""" - client = GateClient(api_key=API_KEY) + client = AgentScoreCore(api_key=API_KEY) assert client.get_signer_verdict(WALLET_A) is None @@ -187,9 +187,9 @@ def _mock_401(code: str, next_steps: dict[str, object] | None = None) -> MagicMo def test_check_raises_token_denied_on_401_expired() -> None: - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError - client = GateClient(api_key=API_KEY) + client = AgentScoreCore(api_key=API_KEY) mock_resp = _mock_401("token_expired", {"action": "deliver_verify_url_and_poll"}) with patch.object(client._sync_client, "post", return_value=mock_resp): try: @@ -202,9 +202,9 @@ def test_check_raises_token_denied_on_401_expired() -> None: def test_check_raises_token_denied_on_401_revoked() -> None: - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError - client = GateClient(api_key=API_KEY) + client = AgentScoreCore(api_key=API_KEY) with patch.object(client._sync_client, "post", return_value=_mock_401("token_expired")): try: client.check(operator_token="opc_revoked") @@ -217,9 +217,9 @@ def test_check_raises_token_denied_on_401_revoked() -> None: def test_check_raises_runtime_error_on_401_unknown_code() -> None: """401 with an unrecognized error code falls through to generic RuntimeError, not TokenDeniedError.""" - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError - client = GateClient(api_key=API_KEY) + client = AgentScoreCore(api_key=API_KEY) with patch.object(client._sync_client, "post", return_value=_mock_401("something_else")): try: client.check(operator_token="opc_odd") @@ -233,9 +233,9 @@ def test_check_raises_runtime_error_on_401_unknown_code() -> None: async def test_acheck_raises_token_denied_on_401() -> None: from unittest.mock import AsyncMock - from agentscore_commerce.identity.client import TokenDeniedError + from agentscore_commerce.identity.core import TokenDeniedError - client = GateClient(api_key=API_KEY) + client = AgentScoreCore(api_key=API_KEY) client._async_client.post = AsyncMock(return_value=_mock_401("token_expired")) try: await client.acheck(operator_token="opc_expired")