getstack 0.18.0__tar.gz → 0.19.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.18.0 → getstack-0.19.0}/PKG-INFO +1 -1
- {getstack-0.18.0 → getstack-0.19.0}/pyproject.toml +1 -1
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/agents.py +3 -2
- getstack-0.19.0/src/getstack/_async/detector_config.py +35 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/reviews.py +5 -1
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/agents.py +6 -2
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/client.py +4 -4
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/detector_config.py +19 -6
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/reviews.py +8 -1
- getstack-0.18.0/src/getstack/_async/detector_config.py +0 -27
- {getstack-0.18.0 → getstack-0.19.0}/.gitignore +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/CLAUDE.md +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/LICENSE +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/README.md +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/scripts/verify_sign_claim_crosslang.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/__init__.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/__init__.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/audit.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/credentials.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/delivery_methods.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/dropoffs.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/evidence_packs.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/identity.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/inbound_webhooks.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/intents.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/llm.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/missions.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/notifications.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/partner_connect.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/partner_tenants.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/passport_session.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/passports.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/proxy.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/scan.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/security_events.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/services.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/skills.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/team.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/_async/usage.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/agent_auth.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/audit.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/auth.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/browser_bootstrap.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/credentials.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/delivery_methods.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/dropoffs.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/errors.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/evidence_packs.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/identity.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/inbound_webhooks.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/intents.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/llm.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/missions.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/notifications.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/partner_connect.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/partner_tenants.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/passport_header_verify.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/passport_session.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/passports.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/proxy.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/py.typed +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/scan.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/security_events.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/services.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/sign_claim.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/skills.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/team.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/types.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/usage.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/src/getstack/verify_offline.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/tests/test_parity.py +0 -0
- {getstack-0.18.0 → getstack-0.19.0}/tests/test_sign_claim.py +0 -0
|
@@ -76,5 +76,6 @@ class AsyncAgentService:
|
|
|
76
76
|
async def delete(self, agent_id: str) -> dict[str, Any]:
|
|
77
77
|
return await self._client.delete(f"/v1/agents/{agent_id}")
|
|
78
78
|
|
|
79
|
-
async def unblock(self, agent_id: str) -> dict[str, Any]:
|
|
80
|
-
|
|
79
|
+
async def unblock(self, agent_id: str, governance_approval_id: str | None = None) -> dict[str, Any]:
|
|
80
|
+
_gov_headers = {"X-Governance-Approval": governance_approval_id} if governance_approval_id else None
|
|
81
|
+
return await self._client.post(f"/v1/agents/{agent_id}/unblock", extra_headers=_gov_headers)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Per-operator detector customization (async parity with the JS SDK's
|
|
2
|
+
DetectorConfigService).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
from urllib.parse import quote
|
|
9
|
+
|
|
10
|
+
from ..client import AsyncHttpClient
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AsyncDetectorConfigService:
|
|
14
|
+
def __init__(self, client: AsyncHttpClient):
|
|
15
|
+
self._client = client
|
|
16
|
+
|
|
17
|
+
async def list(self) -> dict[str, Any]:
|
|
18
|
+
return await self._client.get("/v1/detectors/config")
|
|
19
|
+
|
|
20
|
+
async def get(self, detector_key: str) -> dict[str, Any]:
|
|
21
|
+
return await self._client.get(f"/v1/detectors/{quote(detector_key)}/config")
|
|
22
|
+
|
|
23
|
+
async def upsert(
|
|
24
|
+
self, detector_key: str, governance_approval_id: str | None = None, **config: Any
|
|
25
|
+
) -> dict[str, Any]:
|
|
26
|
+
_gov_headers = {"X-Governance-Approval": governance_approval_id} if governance_approval_id else None
|
|
27
|
+
return await self._client.put(
|
|
28
|
+
f"/v1/detectors/{quote(detector_key)}/config", json=config, extra_headers=_gov_headers
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
async def reset(self, detector_key: str, governance_approval_id: str | None = None) -> None:
|
|
32
|
+
_gov_headers = {"X-Governance-Approval": governance_approval_id} if governance_approval_id else None
|
|
33
|
+
await self._client.delete(
|
|
34
|
+
f"/v1/detectors/{quote(detector_key)}/config", extra_headers=_gov_headers
|
|
35
|
+
)
|
|
@@ -38,13 +38,17 @@ class AsyncReviewService:
|
|
|
38
38
|
decision: str,
|
|
39
39
|
notes: str | None = None,
|
|
40
40
|
block_future: bool = False,
|
|
41
|
+
governance_approval_id: str | None = None,
|
|
41
42
|
) -> ReviewDecisionResult:
|
|
42
43
|
body: dict[str, Any] = {"decision": decision}
|
|
43
44
|
if notes:
|
|
44
45
|
body["notes"] = notes
|
|
45
46
|
if block_future:
|
|
46
47
|
body["block_future"] = True
|
|
47
|
-
|
|
48
|
+
_gov_headers = {"X-Governance-Approval": governance_approval_id} if governance_approval_id else None
|
|
49
|
+
data = await self._client.post(
|
|
50
|
+
f"/v1/passports/reviews/{checkout_id}/decide", json=body, extra_headers=_gov_headers
|
|
51
|
+
)
|
|
48
52
|
return ReviewDecisionResult(
|
|
49
53
|
review_id=data["review_id"],
|
|
50
54
|
agent_id=data["agent_id"],
|
|
@@ -120,5 +120,9 @@ class AgentService:
|
|
|
120
120
|
def delete(self, agent_id: str) -> dict[str, Any]:
|
|
121
121
|
return self._client.delete(f"/v1/agents/{agent_id}")
|
|
122
122
|
|
|
123
|
-
def unblock(self, agent_id: str) -> dict[str, Any]:
|
|
124
|
-
|
|
123
|
+
def unblock(self, agent_id: str, governance_approval_id: str | None = None) -> dict[str, Any]:
|
|
124
|
+
"""GET-230: from API-key sessions this 403s with
|
|
125
|
+
GOVERNANCE_APPROVAL_REQUIRED - retry with governance_approval_id
|
|
126
|
+
after human approval in the dashboard."""
|
|
127
|
+
_gov_headers = {"X-Governance-Approval": governance_approval_id} if governance_approval_id else None
|
|
128
|
+
return self._client.post(f"/v1/agents/{agent_id}/unblock", extra_headers=_gov_headers)
|
|
@@ -72,11 +72,11 @@ class HttpClient:
|
|
|
72
72
|
def patch(self, path: str, json: Any = None) -> Any:
|
|
73
73
|
return self.request("PATCH", path, json=json)
|
|
74
74
|
|
|
75
|
-
def put(self, path: str, json: Any = None) -> Any:
|
|
76
|
-
return self.request("PUT", path, json=json)
|
|
75
|
+
def put(self, path: str, json: Any = None, extra_headers: dict[str, str] | None = None) -> Any:
|
|
76
|
+
return self.request("PUT", path, json=json, extra_headers=extra_headers)
|
|
77
77
|
|
|
78
|
-
def delete(self, path: str) -> Any:
|
|
79
|
-
return self.request("DELETE", path)
|
|
78
|
+
def delete(self, path: str, extra_headers: dict[str, str] | None = None) -> Any:
|
|
79
|
+
return self.request("DELETE", path, extra_headers=extra_headers)
|
|
80
80
|
|
|
81
81
|
def close(self) -> None:
|
|
82
82
|
self._client.close()
|
|
@@ -27,13 +27,26 @@ class DetectorConfigService:
|
|
|
27
27
|
built-in defaults)."""
|
|
28
28
|
return self._client.get(f"/v1/detectors/{quote(detector_key)}/config")
|
|
29
29
|
|
|
30
|
-
def upsert(
|
|
30
|
+
def upsert(
|
|
31
|
+
self, detector_key: str, governance_approval_id: str | None = None, **config: Any
|
|
32
|
+
) -> dict[str, Any]:
|
|
31
33
|
"""Upsert this operator's customization for the named detector.
|
|
32
34
|
studio+ only. Accepts custom_patterns / whitelist_patterns /
|
|
33
|
-
severity_overrides / enabled.
|
|
34
|
-
return self._client.put(f"/v1/detectors/{quote(detector_key)}/config", json=config)
|
|
35
|
+
severity_overrides / enabled.
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
GET-230: loosening changes 403 with GOVERNANCE_APPROVAL_REQUIRED
|
|
38
|
+
from API-key sessions - retry with governance_approval_id after a
|
|
39
|
+
human approves in the dashboard (/governance/approvals)."""
|
|
40
|
+
_gov_headers = {"X-Governance-Approval": governance_approval_id} if governance_approval_id else None
|
|
41
|
+
return self._client.put(
|
|
42
|
+
f"/v1/detectors/{quote(detector_key)}/config", json=config, extra_headers=_gov_headers
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
def reset(self, detector_key: str, governance_approval_id: str | None = None) -> None:
|
|
37
46
|
"""Reset a detector to built-in defaults (deletes the row). studio+
|
|
38
|
-
only.
|
|
39
|
-
|
|
47
|
+
only. GET-230: always requires a governance approval from API-key
|
|
48
|
+
sessions."""
|
|
49
|
+
_gov_headers = {"X-Governance-Approval": governance_approval_id} if governance_approval_id else None
|
|
50
|
+
self._client.delete(
|
|
51
|
+
f"/v1/detectors/{quote(detector_key)}/config", extra_headers=_gov_headers
|
|
52
|
+
)
|
|
@@ -39,13 +39,20 @@ class ReviewService:
|
|
|
39
39
|
decision: str,
|
|
40
40
|
notes: str | None = None,
|
|
41
41
|
block_future: bool = False,
|
|
42
|
+
governance_approval_id: str | None = None,
|
|
42
43
|
) -> ReviewDecisionResult:
|
|
44
|
+
"""GET-230: decision='approved' from API-key sessions 403s with
|
|
45
|
+
GOVERNANCE_APPROVAL_REQUIRED - retry with governance_approval_id
|
|
46
|
+
after human approval. 'blocked' needs no approval."""
|
|
43
47
|
body: dict[str, Any] = {"decision": decision}
|
|
44
48
|
if notes:
|
|
45
49
|
body["notes"] = notes
|
|
46
50
|
if block_future:
|
|
47
51
|
body["block_future"] = True
|
|
48
|
-
|
|
52
|
+
_gov_headers = {"X-Governance-Approval": governance_approval_id} if governance_approval_id else None
|
|
53
|
+
data = self._client.post(
|
|
54
|
+
f"/v1/passports/reviews/{checkout_id}/decide", json=body, extra_headers=_gov_headers
|
|
55
|
+
)
|
|
49
56
|
return ReviewDecisionResult(
|
|
50
57
|
review_id=data["review_id"],
|
|
51
58
|
agent_id=data["agent_id"],
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"""Per-operator detector customization (async parity with the JS SDK's
|
|
2
|
-
DetectorConfigService).
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from typing import Any
|
|
8
|
-
from urllib.parse import quote
|
|
9
|
-
|
|
10
|
-
from ..client import AsyncHttpClient
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class AsyncDetectorConfigService:
|
|
14
|
-
def __init__(self, client: AsyncHttpClient):
|
|
15
|
-
self._client = client
|
|
16
|
-
|
|
17
|
-
async def list(self) -> dict[str, Any]:
|
|
18
|
-
return await self._client.get("/v1/detectors/config")
|
|
19
|
-
|
|
20
|
-
async def get(self, detector_key: str) -> dict[str, Any]:
|
|
21
|
-
return await self._client.get(f"/v1/detectors/{quote(detector_key)}/config")
|
|
22
|
-
|
|
23
|
-
async def upsert(self, detector_key: str, **config: Any) -> dict[str, Any]:
|
|
24
|
-
return await self._client.put(f"/v1/detectors/{quote(detector_key)}/config", json=config)
|
|
25
|
-
|
|
26
|
-
async def reset(self, detector_key: str) -> None:
|
|
27
|
-
await self._client.delete(f"/v1/detectors/{quote(detector_key)}/config")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|