feat(pip): add PolicyClient for RFC-005 PDP integration (Option B)#10
feat(pip): add PolicyClient for RFC-005 PDP integration (Option B)#10
Conversation
Option B architecture: delegates all PDP decision logic to Go core's
EvaluatePolicyDecision RPC. Python SDK handles obligation execution
(context-dependent) and response propagation.
New files:
- capiscio_mcp/pip.py: PolicyClient, PIPConfig, PolicyResult, Obligation
- PolicyClient.evaluate() builds request, calls gRPC, parses response
- PolicyResult.execute_obligations() dispatches to registered handlers
- PolicyResult.allowed/denied/pdp_error convenience properties
- tests/test_pip.py: 23 tests covering:
- PolicyResult properties (allowed/denied/pdp_error)
- Obligation dataclass and execution
- PIPConfig defaults and custom values
- PolicyClient gRPC integration (mock): allow, deny, observe, cache,
break-glass, obligations, bad JSON, request field fidelity
Proto updates:
- Regenerated gen/ stubs from capiscio-core feature/rfc005-pdp-rpc proto
(adds EvaluatePolicyDecision RPC + 6 new message types)
- Updated hand-written stubs with matching dataclasses for IDE support
|
✅ Integration tests passed! capiscio-core gRPC tests working. |
There was a problem hiding this comment.
Pull request overview
Adds the Python Policy Integration Point (PIP) for RFC-005 by introducing a thin PolicyClient that delegates policy decisions to capiscio-core’s new EvaluatePolicyDecision gRPC RPC, returning a PolicyResult with obligations for the SDK to execute.
Changes:
- Added
capiscio_mcp.pipwithPolicyClient,PIPConfig,PolicyResult, and obligation execution support. - Added a new
tests/test_pip.pysuite covering PolicyResult behavior, obligation handling, and mocked gRPC evaluation. - Regenerated/updated proto stubs to include the
EvaluatePolicyDecisionRPC and related message types.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
capiscio_mcp/pip.py |
New PIP client module that builds a PolicyDecisionRequest, calls core via gRPC, parses obligations, and exposes PolicyResult. |
tests/test_pip.py |
New test suite for PIP behavior, obligation execution, and request/response parsing. |
capiscio_mcp/_proto/gen/capiscio/v1/mcp_pb2_grpc.py |
Generated gRPC stub updated with EvaluatePolicyDecision and version gating logic. |
capiscio_mcp/_proto/gen/capiscio/v1/mcp_pb2.py |
Generated protobuf definitions updated to include RFC-005 messages and RPC. |
capiscio_mcp/_proto/capiscio/v1/mcp_pb2_grpc.py |
Hand-written async stub placeholder updated with EvaluatePolicyDecision method signature. |
capiscio_mcp/_proto/capiscio/v1/mcp_pb2.py |
Hand-written placeholder message definitions extended with RFC-005 dataclasses. |
- Regenerated proto stubs from capiscio-core main (PR #43 merged) - PolicyConfig.breakglass_public_key_path (string) → breakglass_public_key (bytes) - Updated PIPConfig, PolicyClient.evaluate(), and tests - Fixed regenerated grpc stub import path
|
✅ Integration tests passed! capiscio-core gRPC tests working. |
- Remove Obligation.id (MCPObligation proto has no id field) - Validate json.loads returns dict before using as params - Downgrade grpcio version check from RuntimeError to RuntimeWarning - Update tests to match proto shape (no id field on obligations)
|
✅ Integration tests passed! capiscio-core gRPC tests working. |
| badge_jti: str = "", | ||
| ial: str = "", | ||
| trust_level: str = "", | ||
| badge_exp: int = 0, |
There was a problem hiding this comment.
trust_level is typed as str and passed directly into PolicySubject.trust_level (a proto string field). Most callers in this codebase represent trust levels as ints/TrustLevel (e.g., GuardResult.trust_level), so passing an int here would raise a TypeError when constructing the protobuf message. Consider accepting int | str (and/or TrustLevel) and normalizing via str(trust_level) before building the request.
| @@ -12,8 +12,8 @@ | |||
| _runtime_version.ValidateProtobufRuntimeVersion( | |||
| _runtime_version.Domain.PUBLIC, | |||
| 6, | |||
| 33, | |||
| 4, | |||
| 31, | |||
| 1, | |||
There was a problem hiding this comment.
The generated protobuf module enforces Protobuf Python Version: 6.31.1 via ValidateProtobufRuntimeVersion(...), which will raise at import time if the runtime protobuf major version is < 6. This is incompatible with the declared dependency floor (protobuf>=4.25.0), so installs that satisfy pyproject.toml can still break at runtime. Either bump the dependency to protobuf>=6.31.1 (or >=6.x) or regenerate the stubs with a protoc/protobuf version that matches the supported protobuf range.
Summary
Adds the Python-side Policy Integration Point (PIP) module for RFC-005, implementing Option B architecture where all PDP decision logic is delegated to the Go core's
EvaluatePolicyDecisiongRPC RPC.Depends on: capiscio-core#43 (Go-side EvaluatePolicyDecision RPC)
Architecture
New Files
capiscio_mcp/pip.pyPolicyClient— thin gRPC caller that buildsPolicyDecisionRequest, sends to core, parsesPolicyDecisionResponsePIPConfig— PDP endpoint, timeout, enforcement mode, PEP ID, workspace, break-glass key pathPolicyResult— decision + obligations + metadata, with convenience properties (allowed,denied,pdp_error)Obligation— parsed obligation with typed params dictPolicyResult.execute_obligations()— dispatches obligations to registered async handlerstests/test_pip.py— 23 testsProto Updates
gen/stubs from capiscio-corefeature/rfc005-pdp-rpcprotoEvaluatePolicyDecisionRPC + 6 new message types (PolicyDecisionRequest/Response, PolicySubject, PolicyAction, PolicyResource, PolicyConfig, MCPObligation)Test Results