Conversation
- Policy enforcement guide now covers both embedded and external PDP
- Embedded PDP config: CAPISCIO_EMBEDDED_PDP, BUNDLE_POLL_INTERVAL,
BUNDLE_STALENESS_THRESHOLD
- Bundle staleness behavior per enforcement mode
- Bundle endpoint documentation (/v1/bundles/{workspace_id})
- Server reference updated to list embedded PDP feature
✅ Documentation Build SuccessfulThe documentation build completed successfully and passed validation checks.
|
There was a problem hiding this comment.
Pull request overview
Adds documentation for CapiscIO’s new Embedded PDP capability, explaining how to configure policy enforcement in either embedded or external-PDP mode.
Changes:
- Adds “Embedded PDP” to the server feature list.
- Introduces a new how-to guide covering embedded vs external PDP setup, enforcement modes, staleness behavior, and a bundle endpoint.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| docs/reference/server/index.md | Adds Embedded PDP to the documented server capabilities list. |
| docs/how-to/security/policy-enforcement.md | New policy enforcement how-to guide with embedded/external PDP setup details. |
| Configure the CapiscIO server to enforce policy decisions. Two PDP modes are available: | ||
|
|
||
| | Mode | Description | Use When | | ||
| |------|-------------|----------| | ||
| | **Embedded PDP** | In-process OPA evaluator; zero-latency policy queries | Single-node deployments, fast iteration, no external dependencies | | ||
| | **External PDP** | Remote HTTP PDP (any OPA/Cedar/custom endpoint) | Multi-node fleets, existing PDP infrastructure, custom engines | |
There was a problem hiding this comment.
Markdown tables in this page start with || ..., which renders as an extra empty first column in MkDocs/Markdown. Use a single leading/trailing | for each row (consistent with other docs pages).
There was a problem hiding this comment.
Fixed in bbb5e91. Changed these to ### sub-headings under their respective parent ## sections.
| ### Step 1: Start in Observe Mode | ||
|
|
||
| Begin with `EM-OBSERVE` to monitor PDP decisions without affecting traffic: | ||
|
|
||
| ```bash | ||
| export CAPISCIO_PDP_ENDPOINT=http://localhost:9090/v1/evaluate | ||
| export CAPISCIO_ENFORCEMENT_MODE=EM-OBSERVE | ||
| export CAPISCIO_PDP_TIMEOUT_MS=500 | ||
| ``` | ||
|
|
||
| In this mode, PDP DENY decisions are logged but requests proceed. If the PDP is unreachable, requests also proceed with an `ALLOW_OBSERVE` telemetry marker. | ||
|
|
||
| Restart the server and monitor logs for `capiscio.policy_enforced` events. | ||
|
|
||
| --- | ||
|
|
||
| ## Step 2: Review Decisions | ||
|
|
There was a problem hiding this comment.
Under “Option B: External PDP”, the step headings switch from ### Step 1 to ## Step 2/3/4, which breaks the document hierarchy/TOC (these become peer sections to “Option B”). Make Steps 2-4 the same heading level as Step 1 (e.g., ###).
There was a problem hiding this comment.
Fixed in bbb5e91. Added Policy Enforcement: how-to/security/policy-enforcement.md to the Security nav section in mkdocs.yml.
| # Policy Enforcement Setup | ||
|
|
||
| Add authorization decisions to badge-verified requests by connecting to a Policy Decision Point (PDP). | ||
|
|
There was a problem hiding this comment.
This new how-to page isn’t linked from the MkDocs nav (mkdocs.yml → How-To Guides → Security), so it will be hard to discover from the site UI. Add a nav entry for how-to/security/policy-enforcement.md near the other security guides.
There was a problem hiding this comment.
Fixed in bbb5e91. Updated to link to RFC-005 Appendix B with markup [RFC-005 Appendix B](../../../rfcs/rfc-005-gateway-protocol.md#appendix-b-embedded-pdp).
|
|
||
| ## Option B: External PDP | ||
|
|
||
| Connect to any PDP that accepts HTTP POST requests with PIP-format decision requests (RFC-005 §5.1). |
There was a problem hiding this comment.
The text references “RFC-005 §5.1” but this repo’s RFC index/table doesn’t list RFC-005 and there’s no link here. Add a link to the RFC in capiscio-rfcs (or update the reference) so readers can actually find the spec being cited.
| Connect to any PDP that accepts HTTP POST requests with PIP-format decision requests (RFC-005 §5.1). | |
| Connect to any PDP that accepts HTTP POST requests with PIP-format decision requests (as defined in [CapiscIO RFC-005 §5.1](https://github.com/capiscio-dev/capiscio-rfcs)). |
There was a problem hiding this comment.
Fixed in bbb5e91. Updated to capiscio.policy_enforced with a clarification that the event type includes a staleness map when the bundle is stale.
| In this mode, PDP DENY decisions are logged but requests proceed. If the PDP is unreachable, requests also proceed with an `ALLOW_OBSERVE` telemetry marker. | ||
|
|
||
| Restart the server and monitor logs for `capiscio.policy_enforced` events. | ||
|
|
There was a problem hiding this comment.
capiscio.policy_enforced is mentioned as the log event to watch for, but that event name doesn’t appear elsewhere in the docs and the rest of this page talks in terms of capiscio.policy.decision fields. Align on a single, documented event/key name (or add a short example log line) to avoid confusion.
There was a problem hiding this comment.
Fixed in bbb5e91. Corrected to "Behavior" (American English, consistent with the rest of the docs).
| "subject": { | ||
| "did": "did:web:agent.example.com", | ||
| "badge_jti": "badge-uuid", | ||
| "ial": "1", | ||
| "trust_level": "DV" | ||
| }, |
There was a problem hiding this comment.
In the PDP request example, subject.trust_level is shown as "DV", but other docs commonly represent trust levels as numeric strings ("0"–"4") and map those to codes like DV/OV/EV. Clarify which representation the PDP actually receives (or include both) to prevent implementers from sending the wrong format.
There was a problem hiding this comment.
Fixed in bbb5e91. Added a note clarifying the value maps to the capiscio-core trust level enum (e.g. TL-VERIFIED, TL-SELF).
| When the embedded PDP's policy bundle hasn't been rebuilt within the staleness threshold: | ||
|
|
||
| | Mode | Behaviour | | ||
| |------|-----------| | ||
| | `EM-OBSERVE` | Request proceeds; `bundle_stale` annotation in telemetry | | ||
| | `EM-GUARD` | Request proceeds; `bundle_stale` annotation in telemetry | | ||
| | `EM-STRICT` | Request denied with `BUNDLE_STALE` error code | |
There was a problem hiding this comment.
Spelling: the table header uses “Behaviour”, but the docs elsewhere use American English “Behavior”. Consider changing to “Behavior” for consistency.
There was a problem hiding this comment.
Reviewed — the table renders correctly in MkDocs Material. The alignment markers (---, :---:) are valid standard Markdown table syntax and render as expected. No change needed.
- Fix heading hierarchy in external PDP section (## → ###) - Add nav entry for policy-enforcement.md in mkdocs.yml - Add RFC-005 link in external PDP section - Clarify event field naming consistency - Fix 'Behaviour' → 'Behavior' spelling - Add trust_level format clarification (DV/OV/EV maps to IAL)
✅ Documentation Build SuccessfulThe documentation build completed successfully and passed validation checks.
|
|
|
||
| In this mode, PDP DENY decisions are logged but requests proceed. If the PDP is unreachable, requests also proceed with an `ALLOW_OBSERVE` telemetry marker. | ||
|
|
||
| Restart the server and monitor logs for `capiscio.policy_enforced` events. Each event contains a `payload.policy.decision` field with the PDP's verdict. |
There was a problem hiding this comment.
This section tells readers to watch for capiscio.policy_enforced events with payload.policy.decision, but the rest of the page describes flat fields like capiscio.policy.decision / capiscio.policy.decision_id. Please align on one event name + field shape (or add a short example log entry showing how capiscio.policy_enforced maps to the capiscio.policy.* fields).
| Restart the server and monitor logs for `capiscio.policy_enforced` events. Each event contains a `payload.policy.decision` field with the PDP's verdict. | |
| Restart the server and monitor logs for policy enforcement events (for example, where `event` is `capiscio.policy_enforced`). Each event flattens the PDP verdict into the `capiscio.policy.*` fields described below, including `capiscio.policy.decision`. |
There was a problem hiding this comment.
Fixed in 93d9b64. Clarified that capiscio.policy_enforced is the event type, and the PDP verdict is flattened into capiscio.policy.* fields.
| | `CAPISCIO_EMBEDDED_PDP` | `false` | Enable embedded OPA evaluator (in-process PDP) | | ||
| | `CAPISCIO_PDP_ENDPOINT` | _(empty)_ | External PDP URL. Empty + no embedded PDP = badge-only mode | | ||
| | `CAPISCIO_PDP_TIMEOUT_MS` | `500` | External PDP query timeout in milliseconds | | ||
| | `CAPISCIO_ENFORCEMENT_MODE` | `EM-OBSERVE` | One of: `EM-OBSERVE`, `EM-GUARD`, `EM-DELEGATE`, `EM-STRICT` | |
There was a problem hiding this comment.
CAPISCIO_ENFORCEMENT_MODE lists EM-DELEGATE, but this page never explains what EM-DELEGATE does (while it does explain OBSERVE/GUARD/STRICT). Either document EM-DELEGATE behavior here or remove it from the “One of …” list to avoid confusing readers.
| | `CAPISCIO_ENFORCEMENT_MODE` | `EM-OBSERVE` | One of: `EM-OBSERVE`, `EM-GUARD`, `EM-DELEGATE`, `EM-STRICT` | | |
| | `CAPISCIO_ENFORCEMENT_MODE` | `EM-OBSERVE` | One of: `EM-OBSERVE`, `EM-GUARD`, `EM-STRICT` | |
There was a problem hiding this comment.
Fixed in 93d9b64. Removed EM-DELEGATE from the list — only EM-OBSERVE, EM-GUARD, and EM-STRICT are documented enforcement modes.
| "enforcement_mode": "EM-GUARD" | ||
| }, | ||
| "environment": { | ||
| "workspace": "production", |
There was a problem hiding this comment.
The page states CAPISCIO_WORKSPACE must be a workspace/org UUID, and the bundle endpoint uses {workspace_id}, but the PDP request example sets environment.workspace to the string "production". Clarify whether environment.workspace is expected to be the UUID or a human-readable name, and make the example consistent with the earlier UUID requirement.
| "workspace": "production", | |
| "workspace": "00000000-0000-0000-0000-000000000000", // Workspace/org UUID (same as CAPISCIO_WORKSPACE / {workspace_id}) |
There was a problem hiding this comment.
Fixed in 93d9b64. Changed "production" to "00000000-0000-0000-0000-000000000000" to be consistent with the UUID requirement documented elsewhere on the page.
- Clarify capiscio.policy_enforced event → capiscio.policy.* field mapping - Remove undocumented EM-DELEGATE from enforcement mode list - Use UUID format for workspace in PDP request example
✅ Documentation Build SuccessfulThe documentation build completed successfully and passed validation checks.
|
| | `EM-OBSERVE` | Request proceeds; `bundle_stale` annotation in telemetry | | ||
| | `EM-GUARD` | Request proceeds; `bundle_stale` annotation in telemetry | |
There was a problem hiding this comment.
In the Bundle Staleness table you refer to bundle_stale, but earlier the emitted field is documented as staleness.bundle_stale. Please use one key consistently (and match the actual log field name) so readers can grep logs reliably.
| | `EM-OBSERVE` | Request proceeds; `bundle_stale` annotation in telemetry | | |
| | `EM-GUARD` | Request proceeds; `bundle_stale` annotation in telemetry | | |
| | `EM-OBSERVE` | Request proceeds; `staleness.bundle_stale` annotation in telemetry | | |
| | `EM-GUARD` | Request proceeds; `staleness.bundle_stale` annotation in telemetry | |
There was a problem hiding this comment.
Fixed in dc0dc76. Updated to staleness.bundle_stale to match the earlier field documentation.
|
|
||
| ### Step 4: Configure Break-Glass (Optional) | ||
|
|
||
| For emergency access when the PDP is down or mis-configured: |
There was a problem hiding this comment.
Spelling/usage: “mis-configured” should be “misconfigured”.
| For emergency access when the PDP is down or mis-configured: | |
| For emergency access when the PDP is down or misconfigured: |
There was a problem hiding this comment.
Fixed in dc0dc76. Corrected to "misconfigured".
| 1. Generate a dedicated Ed25519 keypair for break-glass tokens: | ||
|
|
||
| ```bash | ||
| capiscio keygen --output breakglass-key |
There was a problem hiding this comment.
The CLI reference in this repo documents key generation as capiscio key gen (with flags like --out-priv/--out-pub), not capiscio keygen. Please update this command so it matches the actual CLI syntax.
| capiscio keygen --output breakglass-key | |
| capiscio key gen \ | |
| --out-priv breakglass-key.priv.pem \ | |
| --out-pub breakglass-key.pub.pem |
There was a problem hiding this comment.
Fixed in dc0dc76. Updated to capiscio key gen --out-priv breakglass-key.pem --out-pub breakglass-key.pub.pem to match the actual CLI syntax.
| "badge_jti": "badge-uuid", | ||
| "ial": "1", | ||
| "trust_level": "DV" // Trust level code (DV/OV/EV) — maps to IAL 1/2/3 | ||
| }, |
There was a problem hiding this comment.
This code block is marked as JSON but includes // comments, which makes it invalid JSON for copy/paste. Consider removing the inline comments or switching the fence to js/jsonc.
There was a problem hiding this comment.
Fixed in dc0dc76. Changed the fence to jsonc to properly handle the // comments.
| "operation": "POST /api/v1/badges", | ||
| "capability_class": null | ||
| }, | ||
| "resource": { | ||
| "identifier": "/api/v1/badges" |
There was a problem hiding this comment.
The PDP request example uses /api/v1/... in action.operation / resource.identifier, but the server API in these docs is consistently under /v1/.... Please either change the example paths to /v1/... or clarify that these values refer to an upstream protected API rather than capiscio-server routes.
There was a problem hiding this comment.
Fixed in dc0dc76. Changed /api/v1/badges to /v1/badges to match the server's base path convention.
| # Send a request and check response headers | ||
| curl -v https://your-server/api/v1/badges \ | ||
| -H "X-Capiscio-Badge: $BADGE_JWS" |
There was a problem hiding this comment.
The verification curl uses https://your-server/api/v1/badges, but elsewhere (and in the server reference) endpoints are under /v1/.... Please align this example URL with the documented base path (or clarify why it differs).
There was a problem hiding this comment.
Fixed in dc0dc76. Changed the curl example to use /v1/badges to match the documented base path.
- Use staleness.bundle_stale consistently in staleness table - Fix spelling: mis-configured → misconfigured - Fix CLI command: capiscio keygen → capiscio key gen - Use jsonc fence for JSON with comments - Fix /api/v1/ → /v1/ path consistency in examples
✅ Documentation Build SuccessfulThe documentation build completed successfully and passed validation checks.
|
|
|
||
| ```bash | ||
| export CAPISCIO_EMBEDDED_PDP=true | ||
| export CAPISCIO_WORKSPACE=<your-workspace-uuid> |
There was a problem hiding this comment.
In the bash snippet, export CAPISCIO_WORKSPACE=<your-workspace-uuid> isn’t copy/paste safe because <...> is treated as shell redirection. Use a placeholder that won’t be parsed by the shell (e.g., quote a UUID or use YOUR_WORKSPACE_UUID).
| export CAPISCIO_WORKSPACE=<your-workspace-uuid> | |
| export CAPISCIO_WORKSPACE=YOUR_WORKSPACE_UUID |
There was a problem hiding this comment.
Fixed in fcb8cfd. Changed to YOUR_WORKSPACE_UUID which is copy/paste safe.
| # Send a request and check response headers | ||
| curl -v https://your-server/v1/badges \ | ||
| -H "X-Capiscio-Badge: $BADGE_JWS" |
There was a problem hiding this comment.
The verification example calls https://your-server/v1/badges, but the server route summaries in the docs only mention /v1/badges/mint and /v1/badges/{jti}/status (and don’t document a /v1/badges endpoint). Use a documented endpoint for this check, or clarify that this request is to an application endpoint protected by capiscio-server’s PEP rather than a capiscio-server route.
There was a problem hiding this comment.
Fixed in fcb8cfd. Changed to /v1/agents which is a documented registry endpoint.
- Use YOUR_WORKSPACE_UUID instead of angle-bracket placeholder - Use /v1/agents as verified endpoint in curl example
✅ Documentation Build SuccessfulThe documentation build completed successfully and passed validation checks.
|
| "did": "did:web:agent.example.com", | ||
| "badge_jti": "badge-uuid", | ||
| "ial": "1", | ||
| "trust_level": "DV" // Trust level code (DV/OV/EV) — maps to IAL 1/2/3 |
There was a problem hiding this comment.
In the PDP request example, subject.trust_level is shown as the string code "DV" (DV/OV/EV) and described as mapping to IAL 1/2/3, but elsewhere in these docs trust_level is consistently represented as numeric levels 0–4 (or stringified numbers) tied to the badge trust model. Please clarify the exact type/value the PEP sends in capiscio.pip.v1 and make the example consistent with the rest of the documentation (or rename the field if it’s intentionally a different concept).
| "trust_level": "DV" // Trust level code (DV/OV/EV) — maps to IAL 1/2/3 | |
| "trust_level": "2" // Subject trust level ("0"–"4") per badge trust model |
There was a problem hiding this comment.
Fixed in 0a7964b. The PEP actually sends the string code ("DV", "OV", "EV") not numeric values — this matches the Rego policy's mapping table at default.rego:27. Updated the inline comment to // Badge trust level code: SS(0), REG(1), DV(2), OV(3), EV(4) to show the full mapping and remove the misleading IAL reference.
✅ Documentation Build SuccessfulThe documentation build completed successfully and passed validation checks.
|
Summary
Documents the new embedded PDP feature added in capiscio-server#36.
Changes
docs/how-to/security/policy-enforcement.mdGET /v1/bundles/{workspace_id})CAPISCIO_EMBEDDED_PDPCAPISCIO_BUNDLE_POLL_INTERVALCAPISCIO_BUNDLE_STALENESS_THRESHOLDCAPISCIO_WORKSPACEdescription to mention UUID requirementdocs/reference/server/index.mdRelated