Skip to content

feat: unified PDP plugin — closes #2223#2640

Merged
crivetimihai merged 10 commits intoIBM:mainfrom
yiannis2804:feature/issue-2223-unified-pdp
Feb 2, 2026
Merged

feat: unified PDP plugin — closes #2223#2640
crivetimihai merged 10 commits intoIBM:mainfrom
yiannis2804:feature/issue-2223-unified-pdp

Conversation

@yiannis2804
Copy link
Copy Markdown
Contributor

@yiannis2804 yiannis2804 commented Feb 1, 2026

🔗 Related Issue

Closes #2223

This feature was developed as part of the SWENG Group 5 project (Trinity College Dublin).

📝 Summary

Adds a unified Policy Decision Point plugin that orchestrates access-control decisions across multiple policy engines (Native RBAC, MAC, OPA, Cedar) through a single gateway hook interface. The plugin hooks into tool_pre_invoke and resource_pre_fetch, evaluates the request against enabled engines, and either passes through or blocks with a PluginViolation.


🏷️ Type of Change

  • Bug fix
  • Feature / Enhancement
  • Documentation
  • Refactor
  • Chore (deps, CI, tooling)
  • Other (describe below)

🧪 Verification

Check Command Status
Lint suite make lint ✅ 10/10
Unit tests make test ✅ 46 passed
Coverage ≥ 90% make coverage ⬜ 86% (OPA/Cedar require sidecars)

✅ Checklist

  • Code formatted (make black isort pre-commit)
  • Tests added/updated for changes
  • Documentation updated (if applicable)
  • No secrets or credentials committed

📓 Notes (optional)

@yiannis2804 yiannis2804 force-pushed the feature/issue-2223-unified-pdp branch 4 times, most recently from 48bbb28 to 82e85e8 Compare February 1, 2026 23:08
@crivetimihai crivetimihai self-assigned this Feb 1, 2026
@crivetimihai
Copy link
Copy Markdown
Member

Thanks @yiannis2804 - cool PR. Leave it with me for a bit, I will rebase this to the latest main (as a PR that just bumped unit test coverage from ~63 to 83 was just merged) - and I have a few things I'd like to change as well. Will push the PR back to this branch in a bit, along with the feedback and list of changes.

Cheers!

@crivetimihai crivetimihai added this to the Release 1.0.0-RC1 milestone Feb 1, 2026
@crivetimihai crivetimihai added the tcd SwEng Projects label Feb 1, 2026
yiannis2804 and others added 7 commits February 2, 2026 00:15
Adds a single plugin entry point that orchestrates access-control
decisions across multiple policy engines (Native RBAC, MAC, OPA, Cedar).

- plugins/unified_pdp/unified_pdp.py  — Plugin class, hooks into
  tool_pre_invoke and resource_pre_fetch
- plugins/unified_pdp/pdp.py          — PolicyDecisionPoint orchestrator
- plugins/unified_pdp/pdp_models.py   — Pydantic models (Subject, Resource,
  Context, AccessDecision, config types)
- plugins/unified_pdp/adapter.py      — Abstract engine adapter base class
- plugins/unified_pdp/cache.py        — TTL-aware decision cache
- plugins/unified_pdp/engines/        — Four engine adapters: native_engine,
  mac_engine, opa_engine, cedar_engine
- plugins/unified_pdp/default_rules.json — Starter RBAC ruleset
- tests/unit/plugins/test_unified_pdp.py — 46 unit tests
- plugins/config.yaml                 — Plugin registration (mode: disabled)
- MANIFEST.in                         — Added recursive-include plugins *.json

Combination modes: all_must_allow | any_allow | first_match
Native RBAC and MAC work out of the box. OPA and Cedar require their
respective sidecars (see README).

Closes IBM#2223

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>
13 tests covering UnifiedPDPPlugin hook methods (tool_pre_invoke,
resource_pre_fetch), subject extraction (dict/string/None user),
action string formatting, resource type mapping, and _build_pdp.

unified_pdp.py now at 100% coverage. Remaining gaps are in OPA and
Cedar engine adapters which require external sidecars to test.

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>
Signed-off-by: yiannis2804 <yiannis2804@gmail.com>
- Fix undefined variable eng_type in pdp.py:get_effective_permissions()
- Add shutdown() lifecycle method to UnifiedPDPPlugin to properly close
  HTTP clients for OPA/Cedar engines
- Convert tests from respx to pytest-httpx (project standard)
- Add test for shutdown() method

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
- Remove unused import List from mac_engine.py
- Remove unused variable first_deny from pdp.py

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…view

- Cache key now includes user_agent and context.extra to prevent incorrect
  cached decisions when policies depend on these fields (MAC operation
  override, OPA/Cedar context-based rules)
- Plugin now extracts IP and user_agent from HTTP headers and passes to
  PDP context for policy evaluation
- Plugin passes tool args to context.extra and resource metadata to
  resource.annotations for fine-grained policy checks
- Exception handling in _evaluate_parallel/_evaluate_sequential now
  catches all exceptions (not just TimeoutError/PolicyEvaluationError)
  to prevent crashing the whole request on unexpected errors
- Native RBAC docstring corrected: only JSON files are supported (not YAML)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Extract classification_level from tool args and resource metadata
so MAC engine can make proper Bell-LaPadula decisions instead of
always denying due to missing classification.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai crivetimihai force-pushed the feature/issue-2223-unified-pdp branch from 82e85e8 to f397ff1 Compare February 2, 2026 00:35
@crivetimihai
Copy link
Copy Markdown
Member

crivetimihai commented Feb 2, 2026

@yiannis2804 — Thank you for this substantial contribution! The unified PDP architecture is well-designed with good separation of concerns between the plugin layer, orchestrator, engines, and cache.

I've rebased the branch onto the latest main and made the following fixes:

Fixes Applied

1. Bug: Undefined variable eng_type in pdp.py

The get_effective_permissions() method referenced eng_type but the loop discarded it. Fixed by changing for _, adapter to for eng_type, adapter.

2. Missing shutdown() lifecycle method

Added shutdown() to UnifiedPDPPlugin to properly close HTTP clients for OPA/Cedar engines.

3. Wrong test dependency (respx vs pytest-httpx)

Rewrote tests to use pytest-httpx (the project standard).

4. Linting issues

  • Removed unused import List from mac_engine.py
  • Removed unused variable first_deny from pdp.py

5. Cache key security issue

Cache key now includes user_agent and context.extra to prevent incorrect cached decisions when policies depend on these fields.

6. Plugin context enrichment

  • Extract IP and user_agent from HTTP headers
  • Pass tool args to context.extra
  • Pass metadata to resource.annotations

7. Exception handling

Broadened exception handling in _evaluate_parallel/_evaluate_sequential to catch all exceptions and return default_decision instead of crashing.

8. MAC engine classification_level

Extract classification_level from tool args and resource metadata so MAC engine can make proper Bell-LaPadula decisions.

9. Native RBAC docstring

Corrected docstring to say "JSON file" (removed incorrect YAML claim).

10. Full docstring coverage

Ensure full docstring coverage to pass ruff and interrogate checks

Commits Added

f397ff1d fix(unified-pdp): extract classification_level for MAC engine
e254571a fix(unified-pdp): address review findings from additional security review
dc444975 chore(unified-pdp): fix linting issues
e0e42046 fix(unified-pdp): fix bugs and improve tests

All 60 tests pass. Ready for final review!

Add missing docstrings to all public functions and methods in the
unified_pdp plugin to satisfy the project's 100% docstring coverage
requirement enforced by interrogate.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Add complete Args, Returns, Raises, and Attributes documentation to all
public functions and methods in the unified_pdp plugin, matching the
project's docstring style with full parameter descriptions.

Files updated:
- adapter.py: PolicyEvaluationError, PolicyEngineAdapter methods
- cache.py: _build_cache_key, _CacheEntry, DecisionCache methods
- pdp.py: PolicyDecisionPoint and all evaluation/combination methods
- engines/cedar_engine.py: CedarEngineAdapter and all methods
- engines/mac_engine.py: MACEngineAdapter and all methods
- engines/native_engine.py: NativeRBACAdapter and all methods
- engines/opa_engine.py: OPAEngineAdapter and all methods
- unified_pdp.py: shutdown lifecycle method

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@yiannis2804
Copy link
Copy Markdown
Contributor Author

Thanks @crivetimihai — really appreciate the thorough review and improvements. Everything looks great from my side.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai
Copy link
Copy Markdown
Member

Great, looks like testing passes - merging!

@crivetimihai crivetimihai merged commit 6d65f45 into IBM:main Feb 2, 2026
51 checks passed
@yiannis2804
Copy link
Copy Markdown
Contributor Author

Thanks @crivetimihai — really appreciate the thorough review and improvements. Glad to see this merged!
This was developed by SWENG Group 5, and it’s great to see it land in main.

hughhennelly pushed a commit to hughhennelly/mcp-context-forge that referenced this pull request Feb 8, 2026
* feat: unified PDP plugin for issue IBM#2223

Adds a single plugin entry point that orchestrates access-control
decisions across multiple policy engines (Native RBAC, MAC, OPA, Cedar).

- plugins/unified_pdp/unified_pdp.py  — Plugin class, hooks into
  tool_pre_invoke and resource_pre_fetch
- plugins/unified_pdp/pdp.py          — PolicyDecisionPoint orchestrator
- plugins/unified_pdp/pdp_models.py   — Pydantic models (Subject, Resource,
  Context, AccessDecision, config types)
- plugins/unified_pdp/adapter.py      — Abstract engine adapter base class
- plugins/unified_pdp/cache.py        — TTL-aware decision cache
- plugins/unified_pdp/engines/        — Four engine adapters: native_engine,
  mac_engine, opa_engine, cedar_engine
- plugins/unified_pdp/default_rules.json — Starter RBAC ruleset
- tests/unit/plugins/test_unified_pdp.py — 46 unit tests
- plugins/config.yaml                 — Plugin registration (mode: disabled)
- MANIFEST.in                         — Added recursive-include plugins *.json

Combination modes: all_must_allow | any_allow | first_match
Native RBAC and MAC work out of the box. OPA and Cedar require their
respective sidecars (see README).

Closes IBM#2223

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>

* test: add plugin class unit tests, coverage 86%

13 tests covering UnifiedPDPPlugin hook methods (tool_pre_invoke,
resource_pre_fetch), subject extraction (dict/string/None user),
action string formatting, resource type mapping, and _build_pdp.

unified_pdp.py now at 100% coverage. Remaining gaps are in OPA and
Cedar engine adapters which require external sidecars to test.

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>

* docs: add detailed README for unified PDP plugin

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>

* fix(unified-pdp): fix bugs and improve tests

- Fix undefined variable eng_type in pdp.py:get_effective_permissions()
- Add shutdown() lifecycle method to UnifiedPDPPlugin to properly close
  HTTP clients for OPA/Cedar engines
- Convert tests from respx to pytest-httpx (project standard)
- Add test for shutdown() method

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore(unified-pdp): fix linting issues

- Remove unused import List from mac_engine.py
- Remove unused variable first_deny from pdp.py

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(unified-pdp): address review findings from additional security review

- Cache key now includes user_agent and context.extra to prevent incorrect
  cached decisions when policies depend on these fields (MAC operation
  override, OPA/Cedar context-based rules)
- Plugin now extracts IP and user_agent from HTTP headers and passes to
  PDP context for policy evaluation
- Plugin passes tool args to context.extra and resource metadata to
  resource.annotations for fine-grained policy checks
- Exception handling in _evaluate_parallel/_evaluate_sequential now
  catches all exceptions (not just TimeoutError/PolicyEvaluationError)
  to prevent crashing the whole request on unexpected errors
- Native RBAC docstring corrected: only JSON files are supported (not YAML)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(unified-pdp): extract classification_level for MAC engine

Extract classification_level from tool args and resource metadata
so MAC engine can make proper Bell-LaPadula decisions instead of
always denying due to missing classification.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: add docstrings for 100% interrogate coverage

Add missing docstrings to all public functions and methods in the
unified_pdp plugin to satisfy the project's 100% docstring coverage
requirement enforced by interrogate.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: add comprehensive Google-style docstrings to unified_pdp

Add complete Args, Returns, Raises, and Attributes documentation to all
public functions and methods in the unified_pdp plugin, matching the
project's docstring style with full parameter descriptions.

Files updated:
- adapter.py: PolicyEvaluationError, PolicyEngineAdapter methods
- cache.py: _build_cache_key, _CacheEntry, DecisionCache methods
- pdp.py: PolicyDecisionPoint and all evaluation/combination methods
- engines/cedar_engine.py: CedarEngineAdapter and all methods
- engines/mac_engine.py: MACEngineAdapter and all methods
- engines/native_engine.py: NativeRBACAdapter and all methods
- engines/opa_engine.py: OPAEngineAdapter and all methods
- unified_pdp.py: shutdown lifecycle method

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: add __init__ docstring to PolicyEvaluationError

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: hughhennnelly <hughhennelly06@gmail.com>
kcostell06 pushed a commit to kcostell06/mcp-context-forge that referenced this pull request Feb 24, 2026
* feat: unified PDP plugin for issue IBM#2223

Adds a single plugin entry point that orchestrates access-control
decisions across multiple policy engines (Native RBAC, MAC, OPA, Cedar).

- plugins/unified_pdp/unified_pdp.py  — Plugin class, hooks into
  tool_pre_invoke and resource_pre_fetch
- plugins/unified_pdp/pdp.py          — PolicyDecisionPoint orchestrator
- plugins/unified_pdp/pdp_models.py   — Pydantic models (Subject, Resource,
  Context, AccessDecision, config types)
- plugins/unified_pdp/adapter.py      — Abstract engine adapter base class
- plugins/unified_pdp/cache.py        — TTL-aware decision cache
- plugins/unified_pdp/engines/        — Four engine adapters: native_engine,
  mac_engine, opa_engine, cedar_engine
- plugins/unified_pdp/default_rules.json — Starter RBAC ruleset
- tests/unit/plugins/test_unified_pdp.py — 46 unit tests
- plugins/config.yaml                 — Plugin registration (mode: disabled)
- MANIFEST.in                         — Added recursive-include plugins *.json

Combination modes: all_must_allow | any_allow | first_match
Native RBAC and MAC work out of the box. OPA and Cedar require their
respective sidecars (see README).

Closes IBM#2223

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>

* test: add plugin class unit tests, coverage 86%

13 tests covering UnifiedPDPPlugin hook methods (tool_pre_invoke,
resource_pre_fetch), subject extraction (dict/string/None user),
action string formatting, resource type mapping, and _build_pdp.

unified_pdp.py now at 100% coverage. Remaining gaps are in OPA and
Cedar engine adapters which require external sidecars to test.

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>

* docs: add detailed README for unified PDP plugin

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>

* fix(unified-pdp): fix bugs and improve tests

- Fix undefined variable eng_type in pdp.py:get_effective_permissions()
- Add shutdown() lifecycle method to UnifiedPDPPlugin to properly close
  HTTP clients for OPA/Cedar engines
- Convert tests from respx to pytest-httpx (project standard)
- Add test for shutdown() method

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* chore(unified-pdp): fix linting issues

- Remove unused import List from mac_engine.py
- Remove unused variable first_deny from pdp.py

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(unified-pdp): address review findings from additional security review

- Cache key now includes user_agent and context.extra to prevent incorrect
  cached decisions when policies depend on these fields (MAC operation
  override, OPA/Cedar context-based rules)
- Plugin now extracts IP and user_agent from HTTP headers and passes to
  PDP context for policy evaluation
- Plugin passes tool args to context.extra and resource metadata to
  resource.annotations for fine-grained policy checks
- Exception handling in _evaluate_parallel/_evaluate_sequential now
  catches all exceptions (not just TimeoutError/PolicyEvaluationError)
  to prevent crashing the whole request on unexpected errors
- Native RBAC docstring corrected: only JSON files are supported (not YAML)

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(unified-pdp): extract classification_level for MAC engine

Extract classification_level from tool args and resource metadata
so MAC engine can make proper Bell-LaPadula decisions instead of
always denying due to missing classification.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: add docstrings for 100% interrogate coverage

Add missing docstrings to all public functions and methods in the
unified_pdp plugin to satisfy the project's 100% docstring coverage
requirement enforced by interrogate.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: add comprehensive Google-style docstrings to unified_pdp

Add complete Args, Returns, Raises, and Attributes documentation to all
public functions and methods in the unified_pdp plugin, matching the
project's docstring style with full parameter descriptions.

Files updated:
- adapter.py: PolicyEvaluationError, PolicyEngineAdapter methods
- cache.py: _build_cache_key, _CacheEntry, DecisionCache methods
- pdp.py: PolicyDecisionPoint and all evaluation/combination methods
- engines/cedar_engine.py: CedarEngineAdapter and all methods
- engines/mac_engine.py: MACEngineAdapter and all methods
- engines/native_engine.py: NativeRBACAdapter and all methods
- engines/opa_engine.py: OPAEngineAdapter and all methods
- unified_pdp.py: shutdown lifecycle method

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* docs: add __init__ docstring to PolicyEvaluationError

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: yiannis2804 <yiannis2804@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plugins tcd SwEng Projects

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE][POLICY]: Unified policy decision point (PDP) - Cedar/OPA/native abstraction

2 participants