Skip to content

PR13 — Fix ACTION_PERMISSION_MAP gap for workflow.execute/model.use - #2

Merged
man4ish merged 1 commit into
mainfrom
feature/pr13-dynamic-rbac-activation
Aug 6, 2026
Merged

man4ish merged 1 commit into
mainfrom
feature/pr13-dynamic-rbac-activation

Conversation

@man4ish

@man4ish man4ish commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes a real, verified gap in permission enforcement for gateway-routed traffic: ACTION_PERMISSION_MAP only had an entry for dataset.read. The Gateway's PolicyClient sends action as the literal permission string itself for its 5 mapped services — workflow.execute for workbench/tes/toolserver, model.use for model-registry — never a "tes.*"-prefixed string. Neither literal matched this map nor PREFIX_PERMISSION_MAP's "tes." prefix rule (which only ever matched this repo's own synthetic test fixtures, never real gateway traffic), so required_permission() silently returned None and the PERMISSION gate allowed unconditionally. 4 of 5 gateway-routed services had zero real permission enforcement, regardless of what permissions a caller held — only rag was ever actually enforced.

ACTION_PERMISSION_MAP = {
    "dataset.read": "dataset.read",
    "workflow.execute": "workflow.execute",  # added
    "model.use": "model.use",                # added
}

Both are identity mappings by design — the Gateway pre-resolves action to already be the permission name for its 5 mapped services, so the map's job is confirming "yes, required," not translating.

No other functional change. app/core/rbac.py's "tes." prefix rule is left inert (it's permanently unreachable for real gateway traffic for the same reason) rather than "fixed" to also match workflow.execute — doing so would reintroduce a hardcoded role check, contradicting PR13's own "no hardcoded role-name checks, rely on permissions" direction.

Dependency

This PR is part of PR13 — Dynamic Enterprise RBAC Activation.
It must be reviewed and merged in dependency order with the other PR13 repositories.
Do not merge independently.

Dependency order: auth → policy-engine (this PR) → api-gateway → control-center → studio → docs. Depends on omnibioai-auth's companion PR for real (non-empty) permissions to actually reach this engine in production traffic.

Validation

Tests performed: 90 passed (full suite). New regression-lock tests: test_required_permission_for_workflow_execute_action, test_required_permission_for_model_use_action (unit level), plus two additions to test_engine_permission_tenancy.py using the exact gateway-real action shape (action="workflow.execute"/"model.use", not the "tes.submit"-style shape every prior test used — which is exactly what let this gap ship unnoticed originally).

Security checks: this fix closes an enforcement gap, not a new attack surface — the effect is 4 services moving from "always allowed regardless of permissions" to "correctly gated," strictly narrowing access, never widening it.

Compatibility notes: this repo compiles Cython .so binaries from .py source for IP protection (setup.py build_ext --inplace) — the compiled permissions.cpython-*.so/.c/.o artifacts in this PR were rebuilt from the updated source and are committed alongside it, per this repo's existing convention. No schema, no API surface change.

Related PRs

Part of the PR13 review set, all on feature/pr13-dynamic-rbac-activation:

  • omnibioai-authPR #32 (draft, open) — the dynamic permission source this fix activates
  • omnibioai-api-gateway — tests confirming this repo receives the right permissions per role tier
  • omnibioai-control-centerPR #20 (draft, open)
  • omnibioai-studio — deployment runbook + smoke test exercising this fix end to end
  • omnibioai-docs — documents this exact gap and fix

Review only — do not merge. No migration applied, no deployment performed, live stack untouched.

The Gateway sends the literal permission string as `action` for
workbench/tes/toolserver (workflow.execute) and model-registry
(model.use), which matched neither this map nor the "tes." prefix rule --
4 of 5 gateway-routed services had zero real permission enforcement
regardless of caller permissions. Only rag (dataset.read) was enforced.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@man4ish
man4ish marked this pull request as ready for review August 6, 2026 02:51
@man4ish
man4ish merged commit fed84b8 into main Aug 6, 2026
1 of 2 checks passed
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.

1 participant