getstack 0.19.1__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {getstack-0.19.1 → getstack-1.0.0}/.gitignore +15 -0
- {getstack-0.19.1 → getstack-1.0.0}/CLAUDE.md +2 -1
- {getstack-0.19.1 → getstack-1.0.0}/PKG-INFO +2 -2
- {getstack-0.19.1 → getstack-1.0.0}/pyproject.toml +1 -1
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/__init__.py +28 -0
- getstack-1.0.0/src/getstack/_async/authority.py +269 -0
- getstack-1.0.0/src/getstack/_async/delivery_methods.py +85 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/dropoffs.py +14 -2
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/evidence_packs.py +11 -2
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/identity.py +31 -6
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/llm.py +9 -3
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/missions.py +41 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/partner_tenants.py +1 -1
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/passports.py +26 -0
- getstack-1.0.0/src/getstack/_async/pii_config.py +38 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/proxy.py +3 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/skills.py +22 -2
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/team.py +2 -4
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/usage.py +5 -1
- getstack-1.0.0/src/getstack/_authority_request.py +20 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/agents.py +6 -3
- getstack-1.0.0/src/getstack/authority.py +317 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/client.py +24 -0
- getstack-1.0.0/src/getstack/delivery_methods.py +85 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/dropoffs.py +14 -2
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/errors.py +28 -5
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/evidence_packs.py +10 -2
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/identity.py +31 -6
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/llm.py +16 -7
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/missions.py +33 -52
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/partner_tenants.py +1 -1
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/passport_header_verify.py +41 -24
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/passports.py +26 -0
- getstack-1.0.0/src/getstack/pii_config.py +69 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/proxy.py +5 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/skills.py +28 -3
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/team.py +2 -4
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/types.py +91 -1
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/usage.py +10 -4
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/verify_offline.py +6 -2
- getstack-1.0.0/tests/test_authority.py +323 -0
- getstack-1.0.0/tests/test_delivery_methods.py +77 -0
- getstack-1.0.0/tests/test_dropoffs.py +70 -0
- getstack-1.0.0/tests/test_errors.py +50 -0
- getstack-1.0.0/tests/test_evidence_packs.py +64 -0
- getstack-1.0.0/tests/test_identity_requirements.py +68 -0
- getstack-1.0.0/tests/test_missions.py +134 -0
- {getstack-0.19.1 → getstack-1.0.0}/tests/test_parity.py +115 -0
- getstack-0.19.1/src/getstack/_async/delivery_methods.py +0 -35
- getstack-0.19.1/src/getstack/delivery_methods.py +0 -35
- {getstack-0.19.1 → getstack-1.0.0}/LICENSE +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/README.md +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/scripts/verify_sign_claim_crosslang.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/__init__.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/agents.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/audit.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/credentials.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/detector_config.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/inbound_webhooks.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/intents.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/notifications.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/partner_connect.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/passport_session.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/reviews.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/scan.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/security_events.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/_async/services.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/agent_auth.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/audit.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/auth.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/browser_bootstrap.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/credentials.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/detector_config.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/inbound_webhooks.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/intents.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/notifications.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/partner_connect.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/passport_session.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/py.typed +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/reviews.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/scan.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/security_events.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/services.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/src/getstack/sign_claim.py +0 -0
- {getstack-0.19.1 → getstack-1.0.0}/tests/test_sign_claim.py +0 -0
|
@@ -31,8 +31,13 @@ Thumbs.db
|
|
|
31
31
|
|
|
32
32
|
# Next.js
|
|
33
33
|
.next/
|
|
34
|
+
.next-*/
|
|
34
35
|
out/
|
|
35
36
|
|
|
37
|
+
# Local package-manager cache and temporary preview helpers
|
|
38
|
+
/.pnpm-store/
|
|
39
|
+
/.tmp-*
|
|
40
|
+
|
|
36
41
|
# MCP publisher
|
|
37
42
|
mcp-publisher.exe
|
|
38
43
|
.mcpregistry_*
|
|
@@ -74,3 +79,13 @@ docs/yc-q18/
|
|
|
74
79
|
docs/yc-application-session-preface.md
|
|
75
80
|
*-YC.md
|
|
76
81
|
*-yc.md
|
|
82
|
+
|
|
83
|
+
# Design handoff packages (kept local, never committed)
|
|
84
|
+
STACK website redesign*.zip
|
|
85
|
+
|
|
86
|
+
# Benchmark working files: harvested environments and interim runs. The
|
|
87
|
+
# published artifacts live in docs/benchmarks/.
|
|
88
|
+
scratchpad/
|
|
89
|
+
|
|
90
|
+
# Local venv for the AgentDojo benchmark harness (never commit)
|
|
91
|
+
.venv-agentdojo/
|
|
@@ -14,7 +14,7 @@ Published to PyPI as `getstack`. Not a workspace member of the main monorepo
|
|
|
14
14
|
credentials, drop-offs (+ expire), skills, identity, audit, notifications
|
|
15
15
|
(+ update), security-events, proxy, scan, usage, intents, missions,
|
|
16
16
|
evidence-packs, llm gateway, inbound-webhooks, partner, **team**,
|
|
17
|
-
**delivery_methods**, **detector_config**.
|
|
17
|
+
**delivery_methods**, **detector_config**, **authority**.
|
|
18
18
|
- **Offline / customer-managed crypto** (the JS headline features):
|
|
19
19
|
`verify_passport_offline` (`sdk-python/src/getstack/verify_offline.py` —
|
|
20
20
|
pyjwt/EdDSA, jwks_url OR public_jwk), `verify_passport_header`, and
|
|
@@ -45,6 +45,7 @@ hit `/v1/services/connected` and `/v1/services/{id}/disconnect`. Notification
|
|
|
45
45
|
|
|
46
46
|
- Package metadata: `sdk-python/pyproject.toml`
|
|
47
47
|
- Module entry: `sdk-python/src/getstack/`
|
|
48
|
+
- Authority lifecycle (sync + async): `sdk-python/src/getstack/authority.py`, `sdk-python/src/getstack/_async/authority.py`
|
|
48
49
|
- User-facing quickstart + examples: `sdk-python/README.md`
|
|
49
50
|
- License: `sdk-python/LICENSE`
|
|
50
51
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: getstack
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Python SDK for STACK — trust infrastructure for AI agents
|
|
5
5
|
Project-URL: Homepage, https://getstack.run
|
|
6
6
|
Project-URL: Documentation, https://getstack.run/docs/sdk
|
|
@@ -66,6 +66,9 @@ from .llm import LlmService
|
|
|
66
66
|
from .team import TeamService
|
|
67
67
|
from .delivery_methods import DeliveryMethodService
|
|
68
68
|
from .detector_config import DetectorConfigService
|
|
69
|
+
from .pii_config import PiiConfigService
|
|
70
|
+
from .authority import AuthorityService
|
|
71
|
+
from ._async.authority import AsyncAuthorityService
|
|
69
72
|
from .passport_session import PassportSession
|
|
70
73
|
from .types import (
|
|
71
74
|
Agent,
|
|
@@ -87,6 +90,12 @@ from .types import (
|
|
|
87
90
|
IdentityClaim,
|
|
88
91
|
IdentitySettings,
|
|
89
92
|
VerificationSession,
|
|
93
|
+
SetServiceRequirementInput,
|
|
94
|
+
ServiceRequirement,
|
|
95
|
+
ReplaceServiceRequirementResult,
|
|
96
|
+
AuthorityReference,
|
|
97
|
+
PassportStackClaims,
|
|
98
|
+
VerifiedPassportClaims,
|
|
90
99
|
)
|
|
91
100
|
from .errors import (
|
|
92
101
|
StackError,
|
|
@@ -167,10 +176,19 @@ __all__ = [
|
|
|
167
176
|
"IdentityClaim",
|
|
168
177
|
"IdentitySettings",
|
|
169
178
|
"VerificationSession",
|
|
179
|
+
"SetServiceRequirementInput",
|
|
180
|
+
"ServiceRequirement",
|
|
181
|
+
"ReplaceServiceRequirementResult",
|
|
182
|
+
"AuthorityReference",
|
|
183
|
+
"PassportStackClaims",
|
|
184
|
+
"VerifiedPassportClaims",
|
|
170
185
|
# Service classes (for typing / direct construction)
|
|
171
186
|
"TeamService",
|
|
172
187
|
"DeliveryMethodService",
|
|
173
188
|
"DetectorConfigService",
|
|
189
|
+
"PiiConfigService",
|
|
190
|
+
"AuthorityService",
|
|
191
|
+
"AsyncAuthorityService",
|
|
174
192
|
# Offline / customer-managed crypto (parity with the JS SDK)
|
|
175
193
|
"verify_passport_offline",
|
|
176
194
|
"verify_passport_header",
|
|
@@ -249,6 +267,8 @@ class Stack:
|
|
|
249
267
|
self.team = TeamService(self._client)
|
|
250
268
|
self.delivery_methods = DeliveryMethodService(self._client)
|
|
251
269
|
self.detector_config = DetectorConfigService(self._client)
|
|
270
|
+
self.pii_config = PiiConfigService(self._client)
|
|
271
|
+
self.authority = AuthorityService(self._client)
|
|
252
272
|
|
|
253
273
|
def issue_passport(
|
|
254
274
|
self,
|
|
@@ -258,6 +278,7 @@ class Stack:
|
|
|
258
278
|
intents: list[dict[str, Any]] | None = None,
|
|
259
279
|
ttl_seconds: int | None = None,
|
|
260
280
|
accountability_mode: str | None = None,
|
|
281
|
+
authority_binding_ids: list[str] | None = None,
|
|
261
282
|
**kwargs: Any,
|
|
262
283
|
) -> PassportSession:
|
|
263
284
|
"""Phase 5.2.6 — issue a passport and return a PassportSession
|
|
@@ -274,6 +295,7 @@ class Stack:
|
|
|
274
295
|
if intents is not None: issue_input["intents"] = intents
|
|
275
296
|
if ttl_seconds is not None: issue_input["ttl_seconds"] = ttl_seconds
|
|
276
297
|
if accountability_mode is not None: issue_input["accountability_mode"] = accountability_mode
|
|
298
|
+
if authority_binding_ids is not None: issue_input["authority_binding_ids"] = authority_binding_ids
|
|
277
299
|
issued = self._client.post("/v1/passports/issue", json=issue_input)
|
|
278
300
|
return PassportSession(self._client, issued, issue_input)
|
|
279
301
|
|
|
@@ -396,6 +418,8 @@ class AsyncStack:
|
|
|
396
418
|
from ._async.team import AsyncTeamService
|
|
397
419
|
from ._async.delivery_methods import AsyncDeliveryMethodService
|
|
398
420
|
from ._async.detector_config import AsyncDetectorConfigService
|
|
421
|
+
from ._async.pii_config import AsyncPiiConfigService
|
|
422
|
+
from ._async.authority import AsyncAuthorityService
|
|
399
423
|
from ._async.passport_session import AsyncPassportSession
|
|
400
424
|
|
|
401
425
|
self.agents = AsyncAgentService(self._client)
|
|
@@ -422,6 +446,8 @@ class AsyncStack:
|
|
|
422
446
|
self.team = AsyncTeamService(self._client)
|
|
423
447
|
self.delivery_methods = AsyncDeliveryMethodService(self._client)
|
|
424
448
|
self.detector_config = AsyncDetectorConfigService(self._client)
|
|
449
|
+
self.pii_config = AsyncPiiConfigService(self._client)
|
|
450
|
+
self.authority = AsyncAuthorityService(self._client)
|
|
425
451
|
# Stash for issue_passport() — Python doesn't easily expose the
|
|
426
452
|
# class binding without re-importing inside the method body.
|
|
427
453
|
self._AsyncPassportSession = AsyncPassportSession
|
|
@@ -434,6 +460,7 @@ class AsyncStack:
|
|
|
434
460
|
intents: list[dict[str, Any]] | None = None,
|
|
435
461
|
ttl_seconds: int | None = None,
|
|
436
462
|
accountability_mode: str | None = None,
|
|
463
|
+
authority_binding_ids: list[str] | None = None,
|
|
437
464
|
**kwargs: Any,
|
|
438
465
|
):
|
|
439
466
|
"""Phase 5.2.6 — async passport issue + session wrapper."""
|
|
@@ -442,6 +469,7 @@ class AsyncStack:
|
|
|
442
469
|
if intents is not None: issue_input["intents"] = intents
|
|
443
470
|
if ttl_seconds is not None: issue_input["ttl_seconds"] = ttl_seconds
|
|
444
471
|
if accountability_mode is not None: issue_input["accountability_mode"] = accountability_mode
|
|
472
|
+
if authority_binding_ids is not None: issue_input["authority_binding_ids"] = authority_binding_ids
|
|
445
473
|
issued = await self._client.post("/v1/passports/issue", json=issue_input)
|
|
446
474
|
return self._AsyncPassportSession(self._client, issued, issue_input)
|
|
447
475
|
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"""Async authority principal, proof, binding, receiver, and evidence APIs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ..authority import _idempotency_headers, _version_params
|
|
8
|
+
from ..client import AsyncHttpClient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AsyncAuthorityService:
|
|
12
|
+
"""Async mirror of :class:`getstack.authority.AuthorityService`."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, client: AsyncHttpClient):
|
|
15
|
+
self._client = client
|
|
16
|
+
|
|
17
|
+
async def create_enterprise_oidc_request(
|
|
18
|
+
self, *, idempotency_key: str, **input: Any
|
|
19
|
+
) -> dict[str, Any]:
|
|
20
|
+
"""Create a pending request and return the human approval URL."""
|
|
21
|
+
return await self._client.post(
|
|
22
|
+
"/v1/authority/enterprise-oidc/requests", json=input,
|
|
23
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
async def get_enterprise_oidc_request(self, request_id: str) -> dict[str, Any]:
|
|
27
|
+
return await self._client.get(
|
|
28
|
+
f"/v1/authority/enterprise-oidc/requests/{request_id}"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
async def create_principal(self, *, idempotency_key: str, **input: Any) -> dict[str, Any]:
|
|
32
|
+
data = await self._client.post(
|
|
33
|
+
"/v1/authority/principals", json=input,
|
|
34
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
35
|
+
)
|
|
36
|
+
return data["principal"]
|
|
37
|
+
|
|
38
|
+
async def list_principals(self) -> list[dict[str, Any]]:
|
|
39
|
+
return (await self._client.get("/v1/authority/principals"))["principals"]
|
|
40
|
+
|
|
41
|
+
async def get_principal(self, principal_id: str) -> dict[str, Any]:
|
|
42
|
+
return (await self._client.get(f"/v1/authority/principals/{principal_id}"))["principal"]
|
|
43
|
+
|
|
44
|
+
async def archive_principal(
|
|
45
|
+
self, principal_id: str, *, reason_code: str, idempotency_key: str
|
|
46
|
+
) -> dict[str, Any]:
|
|
47
|
+
data = await self._client.post(
|
|
48
|
+
f"/v1/authority/principals/{principal_id}/archive",
|
|
49
|
+
json={"reason_code": reason_code},
|
|
50
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
51
|
+
)
|
|
52
|
+
return data["principal"]
|
|
53
|
+
|
|
54
|
+
async def erase_principal(
|
|
55
|
+
self, principal_id: str, *, idempotency_key: str
|
|
56
|
+
) -> dict[str, Any]:
|
|
57
|
+
data = await self._client.post(
|
|
58
|
+
f"/v1/authority/principals/{principal_id}/erase", json={},
|
|
59
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
60
|
+
)
|
|
61
|
+
return data["tombstone"]
|
|
62
|
+
|
|
63
|
+
async def import_proof(self, *, idempotency_key: str, **input: Any) -> dict[str, Any]:
|
|
64
|
+
data = await self._client.post(
|
|
65
|
+
"/v1/authority/proofs/import", json=input,
|
|
66
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
67
|
+
)
|
|
68
|
+
return data["proof"]
|
|
69
|
+
|
|
70
|
+
async def create_proof_collection_session(
|
|
71
|
+
self, *, idempotency_key: str, **input: Any
|
|
72
|
+
) -> dict[str, Any]:
|
|
73
|
+
data = await self._client.post(
|
|
74
|
+
"/v1/authority/proof-collection-sessions", json=input,
|
|
75
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
76
|
+
)
|
|
77
|
+
return data["session"]
|
|
78
|
+
|
|
79
|
+
async def get_proof_collection_session(self, session_id: str) -> dict[str, Any]:
|
|
80
|
+
data = await self._client.get(f"/v1/authority/proof-collection-sessions/{session_id}")
|
|
81
|
+
return data["session"]
|
|
82
|
+
|
|
83
|
+
async def list_proofs(self) -> list[dict[str, Any]]:
|
|
84
|
+
return (await self._client.get("/v1/authority/proofs"))["proofs"]
|
|
85
|
+
|
|
86
|
+
async def get_proof(
|
|
87
|
+
self, proof_id: str, *, version: int | None = None
|
|
88
|
+
) -> dict[str, Any]:
|
|
89
|
+
data = await self._client.get(
|
|
90
|
+
f"/v1/authority/proofs/{proof_id}", params=_version_params(version)
|
|
91
|
+
)
|
|
92
|
+
return data["proof"]
|
|
93
|
+
|
|
94
|
+
async def revoke_proof(
|
|
95
|
+
self, proof_id: str, *, reason_code: str, idempotency_key: str
|
|
96
|
+
) -> dict[str, Any]:
|
|
97
|
+
data = await self._client.post(
|
|
98
|
+
f"/v1/authority/proofs/{proof_id}/revoke",
|
|
99
|
+
json={"reason_code": reason_code},
|
|
100
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
101
|
+
)
|
|
102
|
+
return data["proof"]
|
|
103
|
+
|
|
104
|
+
async def erase_proof(self, proof_id: str, *, idempotency_key: str) -> dict[str, Any]:
|
|
105
|
+
data = await self._client.post(
|
|
106
|
+
f"/v1/authority/proofs/{proof_id}/erase", json={},
|
|
107
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
108
|
+
)
|
|
109
|
+
return data["proof"]
|
|
110
|
+
|
|
111
|
+
async def create_binding(self, *, idempotency_key: str, **input: Any) -> dict[str, Any]:
|
|
112
|
+
data = await self._client.post(
|
|
113
|
+
"/v1/authority/bindings", json=input,
|
|
114
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
115
|
+
)
|
|
116
|
+
return data["binding"]
|
|
117
|
+
|
|
118
|
+
async def list_bindings(self) -> list[dict[str, Any]]:
|
|
119
|
+
return (await self._client.get("/v1/authority/bindings"))["bindings"]
|
|
120
|
+
|
|
121
|
+
async def get_binding(
|
|
122
|
+
self, binding_id: str, *, version: int | None = None
|
|
123
|
+
) -> dict[str, Any]:
|
|
124
|
+
data = await self._client.get(
|
|
125
|
+
f"/v1/authority/bindings/{binding_id}", params=_version_params(version)
|
|
126
|
+
)
|
|
127
|
+
return data["binding"]
|
|
128
|
+
|
|
129
|
+
async def create_approval_requests(
|
|
130
|
+
self, binding_id: str, *, idempotency_key: str, **input: Any
|
|
131
|
+
) -> list[dict[str, Any]]:
|
|
132
|
+
data = await self._client.post(
|
|
133
|
+
f"/v1/authority/bindings/{binding_id}/approval-requests", json=input,
|
|
134
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
135
|
+
)
|
|
136
|
+
return data["approval_requests"]
|
|
137
|
+
|
|
138
|
+
async def list_approval_requests(self, binding_id: str) -> list[dict[str, Any]]:
|
|
139
|
+
data = await self._client.get(f"/v1/authority/bindings/{binding_id}/approval-requests")
|
|
140
|
+
return data["approval_requests"]
|
|
141
|
+
|
|
142
|
+
async def activate_binding(
|
|
143
|
+
self, binding_id: str, *, idempotency_key: str, version: int | None = None
|
|
144
|
+
) -> dict[str, Any]:
|
|
145
|
+
data = await self._client.request(
|
|
146
|
+
"POST", f"/v1/authority/bindings/{binding_id}/activate", json={},
|
|
147
|
+
params=_version_params(version),
|
|
148
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
149
|
+
)
|
|
150
|
+
return data["binding"]
|
|
151
|
+
|
|
152
|
+
async def delegate_binding(
|
|
153
|
+
self, binding_id: str, *, idempotency_key: str, **input: Any
|
|
154
|
+
) -> dict[str, Any]:
|
|
155
|
+
data = await self._client.post(
|
|
156
|
+
f"/v1/authority/bindings/{binding_id}/delegate", json=input,
|
|
157
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
158
|
+
)
|
|
159
|
+
return data["binding"]
|
|
160
|
+
|
|
161
|
+
async def revoke_binding(
|
|
162
|
+
self, binding_id: str, *, reason_code: str, idempotency_key: str
|
|
163
|
+
) -> dict[str, Any]:
|
|
164
|
+
data = await self._client.post(
|
|
165
|
+
f"/v1/authority/bindings/{binding_id}/revoke",
|
|
166
|
+
json={"reason_code": reason_code},
|
|
167
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
168
|
+
)
|
|
169
|
+
return data["binding"]
|
|
170
|
+
|
|
171
|
+
async def erase_binding(
|
|
172
|
+
self, binding_id: str, *, idempotency_key: str
|
|
173
|
+
) -> dict[str, Any]:
|
|
174
|
+
data = await self._client.post(
|
|
175
|
+
f"/v1/authority/bindings/{binding_id}/erase", json={},
|
|
176
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
177
|
+
)
|
|
178
|
+
return data["tombstone"]
|
|
179
|
+
|
|
180
|
+
async def create_receiver(self, *, idempotency_key: str, **input: Any) -> dict[str, Any]:
|
|
181
|
+
data = await self._client.post(
|
|
182
|
+
"/v1/authority/receivers", json=input,
|
|
183
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
184
|
+
)
|
|
185
|
+
return data["receiver"]
|
|
186
|
+
|
|
187
|
+
async def list_receivers(self) -> list[dict[str, Any]]:
|
|
188
|
+
return (await self._client.get("/v1/authority/receivers"))["receivers"]
|
|
189
|
+
|
|
190
|
+
async def get_receiver(self, receiver_id: str) -> dict[str, Any]:
|
|
191
|
+
return (await self._client.get(f"/v1/authority/receivers/{receiver_id}"))["receiver"]
|
|
192
|
+
|
|
193
|
+
async def create_receiver_verification_challenge(
|
|
194
|
+
self, receiver_id: str, *, idempotency_key: str
|
|
195
|
+
) -> dict[str, Any]:
|
|
196
|
+
data = await self._client.post(
|
|
197
|
+
f"/v1/authority/receivers/{receiver_id}/verification-challenges", json={},
|
|
198
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
199
|
+
)
|
|
200
|
+
return data["challenge"]
|
|
201
|
+
|
|
202
|
+
async def verify_receiver(
|
|
203
|
+
self, receiver_id: str, *, idempotency_key: str
|
|
204
|
+
) -> dict[str, Any]:
|
|
205
|
+
data = await self._client.post(
|
|
206
|
+
f"/v1/authority/receivers/{receiver_id}/verify", json={},
|
|
207
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
208
|
+
)
|
|
209
|
+
return data["receiver"]
|
|
210
|
+
|
|
211
|
+
async def add_receiver_key(
|
|
212
|
+
self, receiver_id: str, *, idempotency_key: str, **input: Any
|
|
213
|
+
) -> dict[str, Any]:
|
|
214
|
+
data = await self._client.post(
|
|
215
|
+
f"/v1/authority/receivers/{receiver_id}/keys", json=input,
|
|
216
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
217
|
+
)
|
|
218
|
+
return data["key"]
|
|
219
|
+
|
|
220
|
+
async def revoke_receiver_key(
|
|
221
|
+
self, receiver_id: str, key_id: str, *, reason_code: str, idempotency_key: str
|
|
222
|
+
) -> dict[str, Any]:
|
|
223
|
+
data = await self._client.post(
|
|
224
|
+
f"/v1/authority/receivers/{receiver_id}/keys/{key_id}/revoke",
|
|
225
|
+
json={"reason_code": reason_code},
|
|
226
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
227
|
+
)
|
|
228
|
+
return data["key"]
|
|
229
|
+
|
|
230
|
+
async def create_profile_version(
|
|
231
|
+
self, *, idempotency_key: str, **input: Any
|
|
232
|
+
) -> dict[str, Any]:
|
|
233
|
+
data = await self._client.post(
|
|
234
|
+
"/v1/authority/profile-versions", json=input,
|
|
235
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
236
|
+
)
|
|
237
|
+
return data["profile"]
|
|
238
|
+
|
|
239
|
+
async def activate_profile_version(
|
|
240
|
+
self, profile_id: str, *, profile_kind: str, idempotency_key: str
|
|
241
|
+
) -> dict[str, Any]:
|
|
242
|
+
data = await self._client.post(
|
|
243
|
+
f"/v1/authority/profile-versions/{profile_id}/activate",
|
|
244
|
+
json={"profile_kind": profile_kind},
|
|
245
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
246
|
+
)
|
|
247
|
+
return data["profile"]
|
|
248
|
+
|
|
249
|
+
async def list_uses(self) -> list[dict[str, Any]]:
|
|
250
|
+
return (await self._client.get("/v1/authority/uses"))["uses"]
|
|
251
|
+
|
|
252
|
+
async def get_use(self, use_id: str) -> dict[str, Any]:
|
|
253
|
+
return (await self._client.get(f"/v1/authority/uses/{use_id}"))["use"]
|
|
254
|
+
|
|
255
|
+
async def list_presentations(self) -> list[dict[str, Any]]:
|
|
256
|
+
return (await self._client.get("/v1/authority/presentations"))["presentations"]
|
|
257
|
+
|
|
258
|
+
async def get_presentation(self, presentation_id: str) -> dict[str, Any]:
|
|
259
|
+
data = await self._client.get(f"/v1/authority/presentations/{presentation_id}")
|
|
260
|
+
return data["presentation"]
|
|
261
|
+
|
|
262
|
+
async def erase_presentation(
|
|
263
|
+
self, presentation_id: str, *, idempotency_key: str
|
|
264
|
+
) -> dict[str, Any]:
|
|
265
|
+
data = await self._client.post(
|
|
266
|
+
f"/v1/authority/presentations/{presentation_id}/erase", json={},
|
|
267
|
+
extra_headers=_idempotency_headers(idempotency_key),
|
|
268
|
+
)
|
|
269
|
+
return data["tombstone"]
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Notification delivery methods (async parity with the JS SDK's
|
|
2
|
+
DeliveryMethodService).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from ..client import AsyncHttpClient
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AsyncDeliveryMethodService:
|
|
13
|
+
def __init__(self, client: AsyncHttpClient):
|
|
14
|
+
self._client = client
|
|
15
|
+
|
|
16
|
+
async def add(
|
|
17
|
+
self,
|
|
18
|
+
kind: str,
|
|
19
|
+
destination: str,
|
|
20
|
+
governance_approval_id: str | None = None,
|
|
21
|
+
**fields: Any,
|
|
22
|
+
) -> dict[str, Any]:
|
|
23
|
+
body: dict[str, Any] = {
|
|
24
|
+
"channel_type": kind,
|
|
25
|
+
"destination": destination,
|
|
26
|
+
**fields,
|
|
27
|
+
}
|
|
28
|
+
headers = self._approval_headers(governance_approval_id)
|
|
29
|
+
return await self._client.post(
|
|
30
|
+
"/v1/notifications/destinations", json=body, extra_headers=headers
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
async def list(self) -> list[dict[str, Any]]:
|
|
34
|
+
return await self._client.get("/v1/notifications/destinations")
|
|
35
|
+
|
|
36
|
+
async def delete(
|
|
37
|
+
self, destination_id: str, governance_approval_id: str | None = None
|
|
38
|
+
) -> dict[str, Any]:
|
|
39
|
+
return await self._client.delete(
|
|
40
|
+
f"/v1/notifications/destinations/{destination_id}",
|
|
41
|
+
extra_headers=self._approval_headers(governance_approval_id),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
async def rotate_secret(
|
|
45
|
+
self, destination_id: str, governance_approval_id: str | None = None
|
|
46
|
+
) -> dict[str, Any]:
|
|
47
|
+
"""Rotate a webhook secret. The replacement is returned once in this response."""
|
|
48
|
+
return await self._client.post(
|
|
49
|
+
f"/v1/notifications/destinations/{destination_id}/rotate-secret",
|
|
50
|
+
extra_headers=self._approval_headers(governance_approval_id),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
async def send_verification_code(
|
|
54
|
+
self, destination_id: str, governance_approval_id: str | None = None
|
|
55
|
+
) -> dict[str, Any]:
|
|
56
|
+
return await self._client.post(
|
|
57
|
+
f"/v1/notifications/destinations/{destination_id}/send-code",
|
|
58
|
+
extra_headers=self._approval_headers(governance_approval_id),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
async def verify(
|
|
62
|
+
self,
|
|
63
|
+
destination_id: str,
|
|
64
|
+
code: str,
|
|
65
|
+
governance_approval_id: str | None = None,
|
|
66
|
+
) -> dict[str, Any]:
|
|
67
|
+
return await self._client.post(
|
|
68
|
+
f"/v1/notifications/destinations/{destination_id}/verify",
|
|
69
|
+
json={"code": code},
|
|
70
|
+
extra_headers=self._approval_headers(governance_approval_id),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
async def test(
|
|
74
|
+
self, destination_id: str, governance_approval_id: str | None = None
|
|
75
|
+
) -> dict[str, Any]:
|
|
76
|
+
return await self._client.post(
|
|
77
|
+
f"/v1/notifications/destinations/{destination_id}/test",
|
|
78
|
+
extra_headers=self._approval_headers(governance_approval_id),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def _approval_headers(governance_approval_id: str | None) -> dict[str, str] | None:
|
|
83
|
+
if not governance_approval_id:
|
|
84
|
+
return None
|
|
85
|
+
return {"X-Governance-Approval": governance_approval_id}
|
|
@@ -30,10 +30,22 @@ class AsyncDropoffService:
|
|
|
30
30
|
body["on_expire"] = on_expire
|
|
31
31
|
return await self._client.post("/v1/dropoffs", json=body)
|
|
32
32
|
|
|
33
|
-
async def deposit(
|
|
33
|
+
async def deposit(
|
|
34
|
+
self,
|
|
35
|
+
dropoff_id: str,
|
|
36
|
+
data: dict[str, Any],
|
|
37
|
+
agent_id: str,
|
|
38
|
+
passport_jti: str | None = None,
|
|
39
|
+
mission_id: str | None = None,
|
|
40
|
+
) -> dict[str, Any]:
|
|
41
|
+
body: dict[str, Any] = {"agent_id": agent_id, "payload": data}
|
|
42
|
+
if passport_jti is not None:
|
|
43
|
+
body["passport_jti"] = passport_jti
|
|
44
|
+
if mission_id is not None:
|
|
45
|
+
body["mission_id"] = mission_id
|
|
34
46
|
return await self._client.post(
|
|
35
47
|
f"/v1/dropoffs/{dropoff_id}/deposit",
|
|
36
|
-
json=
|
|
48
|
+
json=body,
|
|
37
49
|
)
|
|
38
50
|
|
|
39
51
|
async def collect(self, dropoff_id: str, agent_id: str) -> dict[str, Any]:
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
"""Evidence packs — export, get, list
|
|
1
|
+
"""Evidence packs — export, get, download, list."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
from typing import Any
|
|
7
|
+
from urllib.parse import quote
|
|
7
8
|
|
|
8
9
|
from ..client import AsyncHttpClient
|
|
9
10
|
|
|
@@ -33,7 +34,15 @@ class AsyncEvidencePacksService:
|
|
|
33
34
|
return result
|
|
34
35
|
|
|
35
36
|
async def get(self, pack_id: str) -> dict[str, Any]:
|
|
36
|
-
return await self._client.request(
|
|
37
|
+
return await self._client.request(
|
|
38
|
+
"GET", f"/v1/evidence-packs/{quote(pack_id, safe='')}"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
async def download(self, pack_id: str) -> bytes:
|
|
42
|
+
"""Fetch the exact stored final manifest bytes."""
|
|
43
|
+
return await self._client.request_bytes(
|
|
44
|
+
"GET", f"/v1/evidence-packs/{quote(pack_id, safe='')}/download"
|
|
45
|
+
)
|
|
37
46
|
|
|
38
47
|
async def list(self, *, scope: str | None = None) -> dict[str, Any]:
|
|
39
48
|
path = "/v1/evidence-packs"
|
|
@@ -3,9 +3,18 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from typing import Any
|
|
6
|
+
from urllib.parse import quote
|
|
6
7
|
|
|
7
8
|
from ..client import AsyncHttpClient
|
|
8
|
-
from ..types import
|
|
9
|
+
from ..types import (
|
|
10
|
+
IdentityProvider,
|
|
11
|
+
IdentityClaim,
|
|
12
|
+
IdentitySettings,
|
|
13
|
+
VerificationSession,
|
|
14
|
+
SetServiceRequirementInput,
|
|
15
|
+
ServiceRequirement,
|
|
16
|
+
ReplaceServiceRequirementResult,
|
|
17
|
+
)
|
|
9
18
|
from ..identity import _to_provider, _to_claim
|
|
10
19
|
|
|
11
20
|
|
|
@@ -85,11 +94,27 @@ class AsyncIdentityService:
|
|
|
85
94
|
async def revoke_claim(self, claim_id: str) -> dict[str, Any]:
|
|
86
95
|
return await self._client.delete(f"/v1/identity/claims/{claim_id}")
|
|
87
96
|
|
|
88
|
-
async def get_service_requirements(self, service_id: str) ->
|
|
89
|
-
return await self._client.get(f"/v1/services/{service_id}/requirements")
|
|
97
|
+
async def get_service_requirements(self, service_id: str) -> list[ServiceRequirement]:
|
|
98
|
+
return await self._client.get(f"/v1/services/{quote(service_id, safe='')}/requirements")
|
|
90
99
|
|
|
91
|
-
async def set_service_requirement(self, service_id: str, **kwargs: Any) ->
|
|
92
|
-
return await self._client.post(
|
|
100
|
+
async def set_service_requirement(self, service_id: str, **kwargs: Any) -> ServiceRequirement:
|
|
101
|
+
return await self._client.post(
|
|
102
|
+
f"/v1/services/{quote(service_id, safe='')}/requirements",
|
|
103
|
+
json=kwargs,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
async def replace_service_requirement(
|
|
107
|
+
self,
|
|
108
|
+
service_id: str,
|
|
109
|
+
requirement: SetServiceRequirementInput | None,
|
|
110
|
+
) -> ReplaceServiceRequirementResult:
|
|
111
|
+
return await self._client.put(
|
|
112
|
+
f"/v1/services/{quote(service_id, safe='')}/requirements",
|
|
113
|
+
json={"requirement": requirement},
|
|
114
|
+
)
|
|
93
115
|
|
|
94
116
|
async def delete_service_requirement(self, service_id: str, requirement_id: str) -> None:
|
|
95
|
-
await self._client.delete(
|
|
117
|
+
await self._client.delete(
|
|
118
|
+
f"/v1/services/{quote(service_id, safe='')}/requirements/"
|
|
119
|
+
f"{quote(requirement_id, safe='')}"
|
|
120
|
+
)
|