Skip to content

fix: remove bogus /v1/pdp/evaluate default from PDP config#30

Merged
beonde merged 2 commits into
mainfrom
fix/remove-bogus-pdp-default
May 12, 2026
Merged

fix: remove bogus /v1/pdp/evaluate default from PDP config#30
beonde merged 2 commits into
mainfrom
fix/remove-bogus-pdp-default

Conversation

@beonde
Copy link
Copy Markdown
Member

@beonde beonde commented May 12, 2026

Problem

MCPServerIdentity.connect() was defaulting pdp_endpoint to {server_url}/v1/pdp/evaluate — an endpoint that doesn't exist. This was added yesterday as a WIP placeholder in commit 8b222e3 ("wip: per-request PDP approach (to be replaced by env-var wiring)").

The bogus default caused the guard's Phase 2 org-policy check to silently fail (HTTP 404), meaning org policy overrides (lockdown, selective) had no effect — only hardcoded @guard min_trust_level values applied.

This broke the policy-demo's Phase 2 (Lockdown) and Phase 3 (Selective) scenarios.

Fix

Default pdp_endpoint to empty string instead. Policy evaluation is local: the Go core fetches the OPA bundle via CAPISCIO_BUNDLE_URL and evaluates it with its embedded OPA engine. The pdp_endpoint should only be set when an explicit remote PDP service is deployed.

Architecture reminder

Client (Python SDK)
  └─ @guard decorator
       └─ Phase 1: inline trust-level check (gRPC → Go core EvaluateToolAccess)
       └─ Phase 2: org policy check (gRPC → Go core EvaluatePolicyDecision)
                        └─ Go core loads OPA bundle from CAPISCIO_BUNDLE_URL
                        └─ Evaluates policy LOCALLY with embedded OPA
                        └─ pdp_endpoint is ONLY for optional remote PDP fallback

The pdp_endpoint was defaulting to {server_url}/v1/pdp/evaluate which
does not exist. Policy evaluation is LOCAL: the Go core fetches the
OPA bundle via CAPISCIO_BUNDLE_URL and evaluates it with its embedded
OPA engine. The pdp_endpoint should only be set when an explicit
remote PDP service is deployed.

The bogus default caused the guard's Phase 2 org-policy check to
silently fail (404), meaning org policy overrides (lockdown, selective)
had no effect — only hardcoded @guard min_trust_level values applied.
Copilot AI review requested due to automatic review settings May 12, 2026 05:08
@github-actions
Copy link
Copy Markdown

✅ Integration tests passed! capiscio-core gRPC tests working.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to fix org-policy enforcement configuration during MCPServerIdentity.connect() by removing a previously introduced default PDP endpoint ({server_url}/v1/pdp/evaluate) that does not exist, and by documenting/logging that policy evaluation is intended to be local (via the Go core + OPA bundle) unless a remote PDP is explicitly configured.

Changes:

  • Update connect() parameter docs for pdp_endpoint to describe it as an optional remote PDP URL.
  • Change the effective PDP endpoint default from a derived URL to an empty string.
  • Adjust logging to distinguish between “remote PDP configured” vs “local OPA bundle” modes.

Comment thread capiscio_mcp/connect.py
Comment on lines +310 to +312
Defaults to empty (local OPA bundle evaluation via Go core).
Use ``CAPISCIO_PDP_ENDPOINT`` env var or this param only when
a remote PDP service is explicitly deployed.
Comment thread capiscio_mcp/connect.py
Comment on lines 543 to +562
@@ -553,7 +556,10 @@ async def connect(
workspace=server_id,
)
)
logger.info("Org-policy enforcement enabled: pdp_endpoint=%s", effective_pdp)
if effective_pdp:
logger.info("Remote PDP configured: pdp_endpoint=%s", effective_pdp)
else:
logger.debug("Using local OPA bundle for policy evaluation")
EM-OBSERVE (Go core default) is shadow-mode: logs DENY but allows
through. When connect() sets CAPISCIO_BUNDLE_URL for local OPA
evaluation, it now also defaults CAPISCIO_ENFORCEMENT_MODE to EM-GUARD
so policy decisions are actually enforced.

Callers can still override via the env var for explicit shadow-mode.
@github-actions
Copy link
Copy Markdown

✅ Integration tests passed! capiscio-core gRPC tests working.

@beonde
Copy link
Copy Markdown
Member Author

beonde commented May 12, 2026

Addressing the two Copilot review comments about Phase 2 being disabled when pdp_endpoint is empty:

This is intentional and architecturally correct. The guard has two evaluation phases:

  • Phase 1 (Go core EvaluateToolAccess): Handles badge verification AND local OPA policy evaluation via the pdpClient. This is initialized when the Go binary is built with -tags opa_no_wasm and receives a policy bundle via CAPISCIO_BUNDLE_URL. Phase 1 runs regardless of pdp_endpoint.

  • Phase 2 (Python _evaluate_org_policy): A remote PDP call, gated on pip_cfg.pdp_endpoint being truthy. This is for external/remote policy decision points (future use case).

Before this PR, pdp_endpoint defaulted to f"{server_url}/v1/pdp/evaluate" — a non-existent endpoint that returned 404 silently. Now it defaults to "", which correctly skips the remote Phase 2 call while Phase 1 (local OPA) handles policy enforcement.

The docstring comment about "local OPA bundle evaluation" refers to Phase 1's behavior, not Phase 2. I'll update the docstring for clarity.

Verified end-to-end: the policy-demo runs successfully with EM-GUARD enforcement mode, local OPA bundle loaded, and policies enforced — all via Phase 1.

@beonde beonde merged commit 195edcd into main May 12, 2026
10 checks passed
@beonde beonde deleted the fix/remove-bogus-pdp-default branch May 12, 2026 05:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants