tollgate 1.0.4__tar.gz → 1.0.5__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.
Files changed (60) hide show
  1. {tollgate-1.0.4 → tollgate-1.0.5}/PKG-INFO +1 -1
  2. {tollgate-1.0.4 → tollgate-1.0.5}/pyproject.toml +1 -1
  3. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/__init__.py +3 -2
  4. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/grants.py +46 -0
  5. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/tower.py +2 -1
  6. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_grants.py +19 -0
  7. {tollgate-1.0.4 → tollgate-1.0.5}/.claude/settings.local.json +0 -0
  8. {tollgate-1.0.4 → tollgate-1.0.5}/.gitignore +0 -0
  9. {tollgate-1.0.4 → tollgate-1.0.5}/CHANGELOG.md +0 -0
  10. {tollgate-1.0.4 → tollgate-1.0.5}/COMPARISON.md +0 -0
  11. {tollgate-1.0.4 → tollgate-1.0.5}/CONTRIBUTING.md +0 -0
  12. {tollgate-1.0.4 → tollgate-1.0.5}/LICENSE +0 -0
  13. {tollgate-1.0.4 → tollgate-1.0.5}/Makefile +0 -0
  14. {tollgate-1.0.4 → tollgate-1.0.5}/QUICKSTART.md +0 -0
  15. {tollgate-1.0.4 → tollgate-1.0.5}/README.md +0 -0
  16. {tollgate-1.0.4 → tollgate-1.0.5}/SECURITY.md +0 -0
  17. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mcp_minimal/audit.jsonl +0 -0
  18. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mcp_minimal/demo.py +0 -0
  19. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mcp_minimal/manifest.yaml +0 -0
  20. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mcp_minimal/policy.yaml +0 -0
  21. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mock_tickets/README.md +0 -0
  22. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mock_tickets/agent.py +0 -0
  23. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mock_tickets/demo.py +0 -0
  24. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mock_tickets/manifest.yaml +0 -0
  25. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mock_tickets/tickets.json +0 -0
  26. {tollgate-1.0.4 → tollgate-1.0.5}/examples/mock_tickets/tools.py +0 -0
  27. {tollgate-1.0.4 → tollgate-1.0.5}/examples/strands_minimal/audit.jsonl +0 -0
  28. {tollgate-1.0.4 → tollgate-1.0.5}/examples/strands_minimal/demo.py +0 -0
  29. {tollgate-1.0.4 → tollgate-1.0.5}/examples/strands_minimal/manifest.yaml +0 -0
  30. {tollgate-1.0.4 → tollgate-1.0.5}/examples/strands_minimal/policy.yaml +0 -0
  31. {tollgate-1.0.4 → tollgate-1.0.5}/policies/default.yaml +0 -0
  32. {tollgate-1.0.4 → tollgate-1.0.5}/specs/audit_event.schema.json +0 -0
  33. {tollgate-1.0.4 → tollgate-1.0.5}/specs/decision.schema.json +0 -0
  34. {tollgate-1.0.4 → tollgate-1.0.5}/specs/identity.schema.json +0 -0
  35. {tollgate-1.0.4 → tollgate-1.0.5}/specs/intent.schema.json +0 -0
  36. {tollgate-1.0.4 → tollgate-1.0.5}/specs/tool_request.schema.json +0 -0
  37. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/approvals.py +0 -0
  38. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/audit.py +0 -0
  39. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/exceptions.py +0 -0
  40. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/helpers.py +0 -0
  41. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/integrations/__init__.py +0 -0
  42. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/integrations/mcp.py +0 -0
  43. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/integrations/strands.py +0 -0
  44. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/interceptors/__init__.py +0 -0
  45. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/interceptors/base.py +0 -0
  46. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/interceptors/langchain.py +0 -0
  47. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/interceptors/openai.py +0 -0
  48. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/policy.py +0 -0
  49. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/registry.py +0 -0
  50. {tollgate-1.0.4 → tollgate-1.0.5}/src/tollgate/types.py +0 -0
  51. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_adapters_v1.py +0 -0
  52. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_audit_integrity_v1.py +0 -0
  53. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_deferred_v1.py +0 -0
  54. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_helpers_v1.py +0 -0
  55. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_integrations_v1.py +0 -0
  56. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_policy_v1.py +0 -0
  57. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_registry_v1.py +0 -0
  58. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_security_v1.py +0 -0
  59. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_tower_v1.py +0 -0
  60. {tollgate-1.0.4 → tollgate-1.0.5}/tests/test_v1_integrations.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tollgate
3
- Version: 1.0.4
3
+ Version: 1.0.5
4
4
  Summary: Runtime enforcement layer for AI agent tool calls using Identity + Intent + Policy
5
5
  Author: Tollgate Maintainers
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tollgate"
7
- version = "1.0.4"
7
+ version = "1.0.5"
8
8
  description = "Runtime enforcement layer for AI agent tool calls using Identity + Intent + Policy"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -14,7 +14,7 @@ from .exceptions import (
14
14
  TollgateDenied,
15
15
  TollgateError,
16
16
  )
17
- from .grants import InMemoryGrantStore
17
+ from .grants import GrantStore, InMemoryGrantStore
18
18
  from .helpers import guard, wrap_tool
19
19
  from .policy import PolicyEvaluator, YamlPolicyEvaluator
20
20
  from .registry import ToolRegistry
@@ -33,7 +33,7 @@ from .types import (
33
33
  ToolRequest,
34
34
  )
35
35
 
36
- __version__ = "1.0.4"
36
+ __version__ = "1.0.5"
37
37
 
38
38
  __all__ = [
39
39
  "ControlTower",
@@ -45,6 +45,7 @@ __all__ = [
45
45
  "DecisionType",
46
46
  "Effect",
47
47
  "Grant",
48
+ "GrantStore",
48
49
  "AuditEvent",
49
50
  "Outcome",
50
51
  "ApprovalOutcome",
@@ -1,9 +1,55 @@
1
1
  import asyncio
2
2
  import time
3
+ from typing import Protocol, runtime_checkable
3
4
 
4
5
  from .types import AgentContext, Grant, ToolRequest
5
6
 
6
7
 
8
+ @runtime_checkable
9
+ class GrantStore(Protocol):
10
+ """Protocol for grant storage backends.
11
+
12
+ Implement this protocol to use a custom storage backend (Redis, SQLite, etc.).
13
+
14
+ Example Redis implementation:
15
+
16
+ class RedisGrantStore:
17
+ def __init__(self, redis_client):
18
+ self.redis = redis_client
19
+
20
+ async def create_grant(self, grant: Grant) -> str:
21
+ await self.redis.hset(f"grant:{grant.id}", mapping=grant.to_dict())
22
+ await self.redis.expireat(f"grant:{grant.id}", int(grant.expires_at))
23
+ return grant.id
24
+
25
+ async def find_matching_grant(self, agent_ctx, tool_request) -> Grant | None:
26
+ # Implement matching logic with Redis SCAN or secondary indexes
27
+ ...
28
+
29
+ All methods must be async. The InMemoryGrantStore serves as the reference implementation.
30
+ """
31
+
32
+ async def create_grant(self, grant: Grant) -> str:
33
+ ...
34
+
35
+ async def find_matching_grant(
36
+ self, agent_ctx: AgentContext, tool_request: ToolRequest
37
+ ) -> Grant | None:
38
+ ...
39
+
40
+ async def revoke_grant(self, grant_id: str) -> bool:
41
+ ...
42
+
43
+ async def list_active_grants(self, agent_id: str | None = None) -> list[Grant]:
44
+ ...
45
+
46
+ async def cleanup_expired(self) -> int:
47
+ ...
48
+
49
+ async def get_usage_count(self, grant_id: str) -> int:
50
+ ...
51
+
52
+
7
53
  class InMemoryGrantStore:
8
54
  """In-memory store for action grants with thread-safe matching logic."""
9
55
 
@@ -11,6 +11,7 @@ from .exceptions import (
11
11
  TollgateDeferred,
12
12
  TollgateDenied,
13
13
  )
14
+ from .grants import GrantStore
14
15
  from .policy import PolicyEvaluator
15
16
  from .types import (
16
17
  AgentContext,
@@ -32,7 +33,7 @@ class ControlTower:
32
33
  policy: PolicyEvaluator,
33
34
  approver: Approver,
34
35
  audit: AuditSink,
35
- grant_store: Any | None = None,
36
+ grant_store: GrantStore | None = None,
36
37
  redact_fn: Callable[[dict[str, Any]], dict[str, Any]] | None = None,
37
38
  ):
38
39
  self.policy = policy
@@ -284,3 +284,22 @@ async def test_tower_uses_grant(agent_ctx, tool_req):
284
284
  event = audit.events[-1]
285
285
  assert event.grant_id == grant.id
286
286
  assert event.outcome == Outcome.EXECUTED
287
+
288
+ @pytest.mark.asyncio
289
+ async def test_grant_store_protocol_compliance():
290
+ """Verify InMemoryGrantStore implements GrantStore protocol."""
291
+ from tollgate import GrantStore, InMemoryGrantStore
292
+
293
+ store = InMemoryGrantStore()
294
+
295
+ # Protocol requires these methods exist and are callable
296
+ assert hasattr(store, "create_grant")
297
+ assert hasattr(store, "find_matching_grant")
298
+ assert hasattr(store, "revoke_grant")
299
+ assert hasattr(store, "list_active_grants")
300
+ assert hasattr(store, "cleanup_expired")
301
+ assert hasattr(store, "get_usage_count")
302
+
303
+ # Verify it's recognized as implementing the protocol
304
+ # Note: requires runtime_checkable on GrantStore
305
+ assert isinstance(store, GrantStore)
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