From 91ffdefc6eec81ae4dd4102a1e1fb0eb68c08efc Mon Sep 17 00:00:00 2001 From: man4ish Date: Sun, 4 Oct 2026 01:28:10 -0500 Subject: [PATCH] feat: register provider_keys.manage permission for the gateway's /v1 proxy Reserved -- not yet enforced by any route, the same posture usage.read already has: the real authorization decision for provider-key management is manage_org, checked live by routes_organization_config.py's own require_org_permission_or_ platform_admin dependency, not this registry entry or any JWT permissions claim (org-scoped permissions are never embedded in a token). This just gives omnibioai-api-gateway's new /v1/provider-keys proxy a real, registered name to send as policy-engine context. Co-Authored-By: Claude Sonnet 5 --- app/core/permission_names.py | 23 +++++++++++++++++++++++ tests/test_permission_registry.py | 6 ++++-- tests/test_platform_permissions_api.py | 7 ++++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/app/core/permission_names.py b/app/core/permission_names.py index 5ba6041..200e78f 100644 --- a/app/core/permission_names.py +++ b/app/core/permission_names.py @@ -574,6 +574,29 @@ def _register(perm: PermissionDef) -> None: legacy=False, ) ) +_register( + PermissionDef( + name="provider_keys.manage", + resource="provider_keys", + action="manage", + # M15: same posture usage.read already has -- the gateway sends + # this as context on every /v1/provider-keys/* call (see + # omnibioai-api-gateway's SERVICE_PERMISSION_MAP), but the actual + # authorization decision is manage_org, enforced live and + # independently by app/api/routes_organization_config.py's own + # require_org_permission_or_platform_admin dependency -- not this + # registry entry, and not the JWT permissions claim at all (org- + # scoped permissions are never embedded in a token; they're + # resolved fresh per request against the caller's live + # membership). This vocabulary entry exists so the gateway has a + # real, registered name to send, exactly like usage.read's own + # "first real consumer" story at M1. + scope=PermissionScope.BOTH, + category=PermissionCategory.ORGANIZATION, + description="Reserved -- not yet enforced by any route.", + legacy=False, + ) +) _register( PermissionDef( name="billing.read", diff --git a/tests/test_permission_registry.py b/tests/test_permission_registry.py index 7df0736..12503bc 100644 --- a/tests/test_permission_registry.py +++ b/tests/test_permission_registry.py @@ -47,6 +47,7 @@ "billing.manage": PermissionCategory.BILLING, "subscription.manage": PermissionCategory.BILLING, "marketplace.install": PermissionCategory.MARKETPLACE, + "provider_keys.manage": PermissionCategory.ORGANIZATION, } # omnibioai-workflow-bundles IAM integration: unlike FUTURE_NAMES above, @@ -603,8 +604,9 @@ def test_registry_stats_by_scope_sums_to_total(): # MODEL_REGISTRY_READ_NAMES above) + 1 (toolserver.delegate -- see # DELEGATED_EXECUTION_NAMES above) + 1 (dataset.write -- see # RAG_NAMES above) + 1 (toolserver.register -- see - # DELEGATED_EXECUTION_NAMES above). - assert stats["by_scope"]["both"] == 17 + # DELEGATED_EXECUTION_NAMES above) + 1 (provider_keys.manage -- M15, + # BYOK provider-key storage). + assert stats["by_scope"]["both"] == 18 def test_registry_stats_by_category_sums_to_total(): diff --git a/tests/test_platform_permissions_api.py b/tests/test_platform_permissions_api.py index 1e210c4..95cf722 100644 --- a/tests/test_platform_permissions_api.py +++ b/tests/test_platform_permissions_api.py @@ -39,6 +39,10 @@ "toolserver.register", # HIPAA-V2-001 RAG R1: gates omnibioai-rag's /v1/ingest and /v1/embed. "dataset.write", + # M15: BYOK provider-key storage -- same "reserved -- not yet + # enforced" posture usage.read already has (see + # app/core/permission_names.py's own entry). + "provider_keys.manage", } # #443: kept separate from FUTURE_NAMES above -- that set's own @@ -128,9 +132,10 @@ def test_response_contains_all_registered_permissions(client): # + 1 HIPAA-V2-019 entry (toolserver.register) # + 1 Stripe-hosted payment-method management entry (manage_billing, # the 6th org entry counted above). + # + 1 M15 entry (provider_keys.manage -- BYOK provider-key storage). # PR4's own docs undercounted this as "20" -- corrected here to the # actual registry size rather than perpetuating that error. - assert len(REGISTRY) == 32 + assert len(REGISTRY) == 33 def test_response_fields_match_permission_def_as_dict(client):