Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
EXECUTOR_TYPE = 'thread'
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.261.300"
VERSION = "0.261.301"
IS_DEVELOPMENT = is_development_env_enabled()

# Opt-out for deployments where App Service Easy Auth is active but the platform
Expand Down
53 changes: 51 additions & 2 deletions application/single_app/functions_action_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from functions_action_manifest import bind_action_origin, is_retired_mcp_stdio
from functions_agent_delegation import AGENT_PLUGIN_TYPE, _identifier
from functions_control_center_dashboard import CONTROL_CENTER_ACTION_TYPE


_SCOPES = frozenset({"personal", "group", "global"})
Expand Down Expand Up @@ -158,6 +159,42 @@
return getattr(import_module("config"), f"cosmos_{scope_type}_actions_container")


def _is_control_center_action(action):
action_type = action.get("type") if isinstance(action, dict) else None
return isinstance(action_type, str) and action_type.strip().lower() == CONTROL_CENTER_ACTION_TYPE


def _request_roles():

Check warning on line 167 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
"""The signed-in request's app roles, or none outside a request.

Check warning on line 168 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.

Flask is imported here, with the rest of this module's runtime dependencies, so the
planner projection stays importable without the application.
"""
from flask import has_request_context, session

if not has_request_context():
return []
user = session.get("user") or {}
roles = user.get("roles") if isinstance(user, dict) else None

Check warning on line 178 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
return list(roles) if isinstance(roles, (list, tuple, set, frozenset)) else []

Check warning on line 179 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.


def _control_center_access(settings, user_roles=None):

Check warning on line 182 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
"""Whether the caller may read Control Center insights; no identity means no access.

``user_roles`` should come from the authenticated identity a caller captured. Without it

Check warning on line 185 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
the current request's session is read, and outside a request access is refused.
"""
roles = _request_roles() if user_roles is None else user_roles

Check warning on line 188 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
if not isinstance(roles, (list, tuple, set, frozenset)) or not roles:

Check warning on line 189 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
return False
authentication = import_module("functions_authentication")
capabilities = authentication.get_control_center_capabilities(
{"roles": [str(role) for role in roles]}, settings,

Check warning on line 193 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
)
return bool(capabilities.get("can_view_dashboard"))


def _stored_actions(scope_type, scope_id):
if scope_type == "global":
return _container(scope_type).query_items(
Expand Down Expand Up @@ -256,13 +293,15 @@
}


def build_accessible_action_catalog(user_id, *, settings=None, user_groups=None):
def build_accessible_action_catalog(user_id, *, settings=None, user_groups=None, user_roles=None):

Check warning on line 296 in application/single_app/functions_action_catalog.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
"""Return safe metadata for enabled, governed actions belonging to this actor.

``user_id`` must be captured from authenticated server context, never from plan
arguments. ``user_groups`` may contain group IDs or group records and only
narrows current membership. Global actions retain their own scope and are
available in global mode, or when global/workspace merging is enabled.
``user_roles`` are the caller's authenticated app roles; a Control Center action is
listed only for a caller who may view the Control Center dashboard.
"""
user_id = _require_actor(user_id)
settings = _resolve_settings(settings)
Expand All @@ -281,6 +320,7 @@
group_id = group["id"]
scopes.append(("group", group_id, group.get("name") or "Group"))

control_center_allowed = None
catalog = {}
for scope_type, scope_id, scope_label in scopes:
actions = [
Expand All @@ -293,6 +333,11 @@
feature = "governance_user_actions" if scope_type == "personal" else "governance_group_actions"
actions = governance.filter_actions_by_action_type_access(user_id, actions, feature, scope_type)
for action in actions:
if _is_control_center_action(action):
if control_center_allowed is None:
control_center_allowed = _control_center_access(settings, user_roles)
if scope_type != "global" or not control_center_allowed:
continue
descriptor = _descriptor(action, scope_type, scope_id, scope_label)
catalog.setdefault(descriptor["action_ref"], descriptor)
return list(catalog.values())
Expand Down Expand Up @@ -325,7 +370,7 @@
return projection


def resolve_action_manifest(user_id, action_ref, *, settings=None, user_groups=None):
def resolve_action_manifest(user_id, action_ref, *, settings=None, user_groups=None, user_roles=None):
"""Reauthorize an exact stored ID and return its secret-reference manifest.

No lookup by name, plugin initialization, or workspace-identity hydration is
Expand Down Expand Up @@ -366,6 +411,10 @@
raise LookupError(_UNAVAILABLE)
if not _eligible_record(action, scope_type, scope_id):
raise PermissionError(_UNAVAILABLE)
if _is_control_center_action(action) and (
scope_type != "global" or not _control_center_access(settings, user_roles)
):
raise PermissionError(_UNAVAILABLE)

governance = import_module("functions_governance")
try:
Expand Down
13 changes: 13 additions & 0 deletions application/single_app/functions_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,19 @@ def get_control_center_capabilities(user=None, settings=None):
}


def get_request_control_center_capabilities(settings=None):
"""Return the signed-in request's Control Center capabilities, failing closed outside one.

Agent and orchestration runs re-enter a request context that carries the authenticated
user and roles, so tools invoked from chat are answered here too. A scheduled run has no
signed-in session, so it receives no Control Center access.
"""
if not has_request_context():
return get_control_center_capabilities({}, {})
user = session.get('user') or {}
return get_control_center_capabilities(user, get_settings() if settings is None else settings)


def control_center_required(access_level='admin'):
"""
Unified Control Center access control decorator.
Expand Down
Loading
Loading