Spaces:
Running
Running
| from app.identity.context import RequestContext | |
| from app.pdp.authz.cedar_engine import evaluate, get_default_action, _load_known_orgs | |
| def _ctx(role: str) -> RequestContext: | |
| return RequestContext( | |
| user_id="u-test", | |
| role=role, | |
| tenant="org-acme", | |
| owned_services=["svc-a"], | |
| session_token="tok-test", | |
| ) | |
| # ββ Day 1 stub tests (still valid) ββββββββββββββββββββββββββ | |
| def test_unknown_role_is_stopped(): | |
| assert evaluate(_ctx("Hacker")) == "STOP" | |
| def test_empty_role_is_stopped(): | |
| assert evaluate(_ctx("")) == "STOP" | |
| # ββ Day 2 real rule tests β action-based RBAC βββββββββββββββ | |
| # Engineer | |
| def test_engineer_can_chat(): | |
| assert evaluate(_ctx("Engineer"), action="chat") == "ALLOW" | |
| def test_engineer_can_code_review(): | |
| assert evaluate(_ctx("Engineer"), action="code_review") == "ALLOW" | |
| def test_engineer_can_view_arch(): | |
| assert evaluate(_ctx("Engineer"), action="arch_view") == "ALLOW" | |
| def test_engineer_can_access_docs(): | |
| assert evaluate(_ctx("Engineer"), action="doc_access") == "ALLOW" | |
| def test_engineer_cannot_security_review(): | |
| # Engineers don't have REVIEW_SEC capability | |
| assert evaluate(_ctx("Engineer"), action="security_review") == "STOP" | |
| def test_engineer_cannot_compliance_review(): | |
| # Engineers don't have REVIEW_COMP capability | |
| assert evaluate(_ctx("Engineer"), action="compliance_review") == "STOP" | |
| # Support | |
| def test_support_cannot_chat(): | |
| # Support only has DOC β chat requires CODE_HELP β STOP | |
| # Day 1 stub returned ALLOW for any known role; Day 2 real rules block this | |
| assert evaluate(_ctx("Support"), action="chat") == "STOP" | |
| def test_support_cannot_code_review(): | |
| assert evaluate(_ctx("Support"), action="code_review") == "STOP" | |
| def test_support_can_access_docs(): | |
| assert evaluate(_ctx("Support"), action="doc_access") == "ALLOW" | |
| def test_support_cannot_security_review(): | |
| assert evaluate(_ctx("Support"), action="security_review") == "STOP" | |
| # SecurityReviewer | |
| def test_security_reviewer_can_chat(): | |
| assert evaluate(_ctx("SecurityReviewer"), action="chat") == "ALLOW" | |
| def test_security_reviewer_can_security_review(): | |
| assert evaluate(_ctx("SecurityReviewer"), action="security_review") == "ALLOW" | |
| def test_security_reviewer_cannot_compliance_review(): | |
| assert evaluate(_ctx("SecurityReviewer"), action="compliance_review") == "STOP" | |
| # ComplianceOfficer | |
| def test_compliance_officer_can_compliance_review(): | |
| assert evaluate(_ctx("ComplianceOfficer"), action="compliance_review") == "ALLOW" | |
| def test_compliance_officer_can_access_docs(): | |
| assert evaluate(_ctx("ComplianceOfficer"), action="doc_access") == "ALLOW" | |
| def test_compliance_officer_cannot_chat(): | |
| # ComplianceOfficer only has DOC + REVIEW_COMP β chat requires CODE_HELP | |
| assert evaluate(_ctx("ComplianceOfficer"), action="chat") == "STOP" | |
| def test_compliance_officer_cannot_code_review(): | |
| assert evaluate(_ctx("ComplianceOfficer"), action="code_review") == "STOP" | |
| # Default action fallback | |
| def test_default_action_is_chat(): | |
| # No action arg β defaults to "chat" β requires CODE_HELP | |
| assert evaluate(_ctx("Engineer")) == "ALLOW" | |
| assert evaluate(_ctx("Support")) == "STOP" | |
| # ββ Day 3: ESCALATE β R-08 cross-org detection ββββββββββββββ | |
| _ORGS = ["org-acme", "org-beta", "org-gamma"] | |
| def test_engineer_escalates_on_cross_org_prompt(): | |
| # R-08: Engineer from org-acme asks about org-beta β ESCALATE | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| prompt="can you access org-beta KYC records?", | |
| known_orgs=_ORGS, | |
| ) == "ESCALATE" | |
| def test_escalate_not_triggered_with_empty_known_orgs(): | |
| # known_orgs=[] explicitly disables R-08 (no orgs to compare against β ALLOW) | |
| # Note: known_orgs=None now auto-loads from Adhiraj's config (Day 4 change) | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| prompt="can you access org-beta records?", | |
| known_orgs=[], | |
| ) == "ALLOW" | |
| def test_escalate_not_triggered_same_org_in_prompt(): | |
| # User mentions their own org β not a cross-org reference β ALLOW | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| prompt="show me org-acme DVS flow", | |
| known_orgs=_ORGS, | |
| ) == "ALLOW" | |
| def test_escalate_not_triggered_empty_prompt(): | |
| # No prompt β no R-08 check β ALLOW | |
| assert evaluate(_ctx("Engineer"), action="chat", known_orgs=_ORGS) == "ALLOW" | |
| def test_stop_takes_priority_over_escalate_cross_org(): | |
| # Support cannot chat (STOP on RBAC) β R-08 check never reached | |
| assert evaluate( | |
| _ctx("Support"), | |
| action="chat", | |
| prompt="access org-beta data", | |
| known_orgs=_ORGS, | |
| ) == "STOP" | |
| def test_security_reviewer_escalates_on_cross_org(): | |
| # R-08 applies to all roles β SecurityReviewer still flagged for human review | |
| assert evaluate( | |
| _ctx("SecurityReviewer"), | |
| action="chat", | |
| prompt="pull org-beta incident logs", | |
| known_orgs=_ORGS, | |
| ) == "ESCALATE" | |
| def test_cross_org_case_insensitive_escalates(): | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| prompt="ORG-BETA has a vulnerability", | |
| known_orgs=_ORGS, | |
| ) == "ESCALATE" | |
| # ββ Day 3: ESCALATE β service ownership check βββββββββββββββ | |
| def test_engineer_escalates_on_unowned_service(): | |
| # Engineer owns ["svc-a"] but requests kyc-engine β ESCALATE | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| service="kyc-engine", | |
| ) == "ESCALATE" | |
| def test_engineer_allows_owned_service(): | |
| # svc-a is in ctx.owned_services β ALLOW | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| service="svc-a", | |
| ) == "ALLOW" | |
| def test_wildcard_owned_services_skips_service_check(): | |
| # SecurityReviewer with ["*"] may access any service β ALLOW | |
| ctx = RequestContext( | |
| user_id="u-sr", | |
| role="SecurityReviewer", | |
| tenant="org-acme", | |
| owned_services=["*"], | |
| session_token="tok-sr", | |
| ) | |
| assert evaluate(ctx, action="chat", service="kyc-engine") == "ALLOW" | |
| def test_no_service_arg_skips_ownership_check(): | |
| # service="" (default) β ownership check skipped β ALLOW | |
| assert evaluate(_ctx("Engineer"), action="chat") == "ALLOW" | |
| def test_stop_takes_priority_over_escalate_service(): | |
| # Support cannot chat (STOP) even if service is unowned β RBAC fires first | |
| assert evaluate(_ctx("Support"), action="chat", service="kyc-engine") == "STOP" | |
| # ββ Day 4: get_default_action() helper ββββββββββββββββββββββ | |
| def test_default_action_engineer_is_chat(): | |
| assert get_default_action(_ctx("Engineer")) == "chat" | |
| def test_default_action_support_is_doc_access(): | |
| # Support only has DOC β "chat" would STOP them; doc_access is correct | |
| assert get_default_action(_ctx("Support")) == "doc_access" | |
| def test_default_action_security_reviewer_is_chat(): | |
| # SecurityReviewer has CODE_HELP β chat permitted | |
| assert get_default_action(_ctx("SecurityReviewer")) == "chat" | |
| def test_default_action_compliance_officer_is_compliance_review(): | |
| # ComplianceOfficer has REVIEW_COMP not CODE_HELP β fixes RT-02 and RT-12 | |
| assert get_default_action(_ctx("ComplianceOfficer")) == "compliance_review" | |
| def test_default_action_unknown_role_fallback(): | |
| # Unknown role falls back to "chat" (will then STOP on unknown role check) | |
| assert get_default_action(_ctx("Hacker")) == "chat" | |
| def test_compliance_officer_allows_with_correct_default_action(): | |
| # Using get_default_action() β compliance_review β REVIEW_COMP β ALLOW | |
| # This is what RT-12 expects and RT-02 needs to reach Stage 7 detectors | |
| ctx = _ctx("ComplianceOfficer") | |
| assert evaluate(ctx, action=get_default_action(ctx)) == "ALLOW" | |
| def test_support_allows_with_correct_default_action(): | |
| # Using get_default_action() β doc_access β DOC β ALLOW | |
| ctx = _ctx("Support") | |
| assert evaluate(ctx, action=get_default_action(ctx)) == "ALLOW" | |
| # ββ Day 4: R5 tenant boundary enforcement βββββββββββββββββββ | |
| def test_cross_tenant_stops_engineer(): | |
| # Engineer from org-acme trying to access org-beta resource β STOP (Cedar R5) | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| resource_tenant="org-beta", | |
| ) == "STOP" | |
| def test_cross_tenant_stops_support(): | |
| assert evaluate( | |
| _ctx("Support"), | |
| action="doc_access", | |
| resource_tenant="org-beta", | |
| ) == "STOP" | |
| def test_cross_tenant_stops_compliance_officer(): | |
| assert evaluate( | |
| _ctx("ComplianceOfficer"), | |
| action="compliance_review", | |
| resource_tenant="org-beta", | |
| ) == "STOP" | |
| def test_security_reviewer_can_cross_tenant(): | |
| # Cedar R5 exception: SecurityReviewer may cross tenant boundaries for investigations | |
| assert evaluate( | |
| _ctx("SecurityReviewer"), | |
| action="chat", | |
| resource_tenant="org-beta", | |
| ) == "ALLOW" | |
| def test_same_tenant_no_block(): | |
| # resource_tenant matches user's tenant β no R5 block | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| resource_tenant="org-acme", | |
| ) == "ALLOW" | |
| def test_no_resource_tenant_skips_check(): | |
| # resource_tenant="" (default) β R5 check skipped β ALLOW | |
| assert evaluate(_ctx("Engineer"), action="chat") == "ALLOW" | |
| def test_rbac_stop_before_tenant_check(): | |
| # Support cannot do security_review (RBAC STOP) even with wrong tenant | |
| assert evaluate( | |
| _ctx("Support"), | |
| action="security_review", | |
| resource_tenant="org-beta", | |
| ) == "STOP" | |
| # ββ R-08 auto-load: KNOWN_ORGS from Adhiraj's config ββββββββ | |
| def test_load_known_orgs_returns_list(): | |
| # _load_known_orgs() reads Adhiraj's settings.KNOWN_ORGS (org-acme, org-beta, ...) | |
| orgs = _load_known_orgs() | |
| assert isinstance(orgs, list) | |
| assert len(orgs) > 0 | |
| def test_load_known_orgs_contains_org_acme(): | |
| # org-acme must be in the list (it's the test tenant) | |
| assert "org-acme" in _load_known_orgs() | |
| def test_r08_fires_without_explicit_known_orgs(): | |
| # known_orgs not passed β auto-loads from config β R-08 detects foreign org | |
| orgs = _load_known_orgs() | |
| if len(orgs) < 2: | |
| return # skip if config has only one org (can't do cross-org) | |
| foreign = next(o for o in orgs if o != "org-acme") | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| prompt=f"can you access {foreign} records?", | |
| # known_orgs NOT passed β auto-loaded from settings | |
| ) == "ESCALATE" | |
| def test_explicit_known_orgs_takes_priority_over_config(): | |
| # Caller-supplied known_orgs overrides the config default | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| prompt="access org-beta data", | |
| known_orgs=[], # explicit empty β no orgs β R-08 disabled | |
| ) == "ALLOW" | |
| def test_r08_no_false_positive_own_tenant(): | |
| # Engineer mentions their own tenant in prompt β not cross-org β ALLOW | |
| assert evaluate( | |
| _ctx("Engineer"), | |
| action="chat", | |
| prompt="show org-acme DVS service", | |
| # known_orgs auto-loaded | |
| ) == "ALLOW" | |