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 @@ -100,7 +100,7 @@
EXECUTOR_TYPE = 'thread'
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.261.217"
VERSION = "0.261.221"
IS_DEVELOPMENT = is_development_env_enabled()

# Opt-out for deployments where App Service Easy Auth is active but the platform
Expand Down
2 changes: 1 addition & 1 deletion application/single_app/functions_agent_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
_MANIFEST_FIELDS = frozenset({
"id", "name", "displayName", "type", "description", "is_enabled", "identity_id",
"endpoint", "auth", "metadata", "additionalFields", "user_id", "group_id",
"is_global", "is_group", "scope", "created_at", "created_by", "modified_at",
"is_global", "is_group", "scope", "scope_id", "created_at", "created_by", "modified_at",
"modified_by", "updated_at", "last_updated", "_attachments", "_etag", "_rid",
"_self", "_ts", "_delegation_scope_type", "_delegation_scope_id",
})
Expand Down
4 changes: 2 additions & 2 deletions application/single_app/functions_documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -6822,6 +6822,8 @@
return None

try:
# The status write changes this record's etag, so it must precede the read that guards the final write.
update_callback(status=f"Uploading {blob_filename} to Blob Storage...")

Check warning on line 6826 in application/single_app/functions_documents.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
cosmos_container = _get_documents_container(group_id=group_id, public_workspace_id=public_workspace_id)
current_document = cosmos_container.read_item(item=document_id, partition_key=document_id)
storage_account_container_name = current_document.get("blob_container") or _get_blob_container_name(
Expand Down Expand Up @@ -6875,8 +6877,6 @@

metadata = {k: v for k, v in metadata.items() if v is not None}

update_callback(status=f"Uploading {blob_filename} to Blob Storage...")

with open(temp_file_path, "rb") as f:
blob_client.upload_blob(f, overwrite=True, metadata=metadata)

Expand Down
43 changes: 42 additions & 1 deletion application/single_app/functions_simplechat_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2059,10 +2059,12 @@
if not is_group_collaboration_conversation(conversation_doc):
raise LookupError(CONVERSATION_ACCESS_ERROR)

group_id = str(((conversation_doc.get("scope") or {}).get("group_id")) or "").strip()

Check warning on line 2062 in application/single_app/functions_simplechat_operations.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.
participants_to_add = _build_invited_participants(
creator_user=current_user,
participants=participants,
participant_identifiers=participant_identifiers,
group_members=_group_member_summaries(find_group_by_id(group_id) if group_id else None),
)
if not participants_to_add:
raise ValueError("At least one participant identifier is required")
Expand Down Expand Up @@ -2339,6 +2341,7 @@
creator_user: Dict[str, str],
participants: Optional[Iterable[Dict[str, Any]]] = None,
participant_identifiers: Any = None,
group_members: Optional[List[Dict[str, str]]] = None,
) -> List[Dict[str, str]]:
invited_participants: List[Dict[str, str]] = []
seen_user_ids = {creator_user.get("user_id")}
Expand All @@ -2354,7 +2357,9 @@
invited_participants.append(normalized_participant)

for raw_identifier in _split_participant_identifiers(participant_identifiers):
resolved_user = resolve_directory_user(user_identifier=raw_identifier)
resolved_user = _match_group_member(group_members, raw_identifier)
if resolved_user is None:
resolved_user = resolve_directory_user(user_identifier=raw_identifier)
normalized_participant = normalize_collaboration_user(resolved_user)
if not normalized_participant:
continue
Expand All @@ -2367,6 +2372,42 @@
return invited_participants


def _group_member_summaries(group_doc: Optional[Dict[str, Any]]) -> List[Dict[str, str]]:
"""The group's owner and members as collaboration user summaries, once each."""
if not isinstance(group_doc, dict):
return []
owner = group_doc.get("owner") if isinstance(group_doc.get("owner"), dict) else {}
raw_members = [
{"userId": owner.get("id"), "displayName": owner.get("displayName"), "email": owner.get("email")},
*(group_doc.get("users") or []),
]
members: Dict[str, Dict[str, str]] = {}
for raw_member in raw_members:
summary = normalize_collaboration_user(raw_member)
if summary:
members.setdefault(summary["user_id"], summary)
return list(members.values())


def _match_group_member(group_members: Optional[List[Dict[str, str]]], identifier: str) -> Optional[Dict[str, str]]:
"""The one group member an invite identifier names by user ID, email or display name.

Matching the group's own records needs no directory lookup, which a scheduled
workflow run cannot make. An identifier that names no member, or several, is left
to the directory.
"""
wanted = str(identifier or "").strip().lower()
matches = [
member for member in group_members or []
if wanted in {
str(member.get("user_id") or "").lower(),
str(member.get("email") or "").lower(),
str(member.get("display_name") or "").lower(),
}
]
return matches[0] if len(matches) == 1 else None


def _split_participant_identifiers(raw_identifiers: Any) -> List[str]:
if raw_identifiers is None:
return []
Expand Down
27 changes: 25 additions & 2 deletions application/single_app/functions_workflow_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@
is_cross_format_compare_one_to_many_enabled,
is_tabular_processing_enabled,
normalize_model_endpoints,
read_user_settings_snapshot,
resolve_model_endpoint_foundry_scope,
)
from functions_tabular_parity_contract import (
Expand Down Expand Up @@ -5909,6 +5910,27 @@
return _workflow_runner_app


def _workflow_owner_identity(user_id):
"""Return the owner's stored display name and email for a run without a signed-in session.

Without them a background run acts as the bare object ID, which then shows as the name
on the groups and messages it creates and is written back over the stored display name.
"""
if not user_id:
return '', ''
try:

Check warning on line 5921 in application/single_app/functions_workflow_runner.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 run acts as this owner, whose id comes from the stored workflow rather than a caller.
user_doc = read_user_settings_snapshot(user_id, allow_cross_user=True)
except AzureError as exc:
log_event(

Check warning on line 5925 in application/single_app/functions_workflow_runner.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.
'[WorkflowRunner] Owner profile unavailable for a background run',
extra={'user_id': user_id, 'error_type': type(exc).__name__},
level=logging.WARNING,
)
return '', ''
return str(user_doc.get('display_name') or '').strip(), str(user_doc.get('email') or '').strip()


@contextmanager
def _ensure_execution_context(user_id):
created_context = None
Expand All @@ -5920,13 +5942,14 @@
reuse_existing = session_user_id == str(user_id or '').strip()

if not reuse_existing:
display_name, email = _workflow_owner_identity(str(user_id or '').strip())
created_context = _get_workflow_runner_app().test_request_context('/api/internal/workflows/run')
created_context.push()
session['user'] = {
'oid': user_id,
'roles': ['User'],
'preferred_username': '',
'name': user_id,
'preferred_username': email,
'name': display_name or user_id,
}

try:
Expand Down
3 changes: 2 additions & 1 deletion application/single_app/model_endpoint_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@


ANTHROPIC_MODEL_MARKERS = ("claude",)
OPENAI_REASONING_MODEL_PREFIXES = ("gpt-5", "o1", "o3", "o4")
OPENAI_REASONING_MODEL_PREFIXES = ("gpt-5", "gpt-6", "o1", "o3", "o4")

Check warning on line 70 in application/single_app/model_endpoint_clients.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
MODEL_CONTEXT_MODE_SYSTEM = "system"
MODEL_CONTEXT_MODE_FOLD_LATEST_USER = "fold_latest_user"

Expand Down Expand Up @@ -111,6 +111,7 @@
return (
normalized_model_name.startswith(OPENAI_REASONING_MODEL_PREFIXES)
or "gpt-5" in normalized_model_name
or "gpt-6" in normalized_model_name
)

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,20 +476,22 @@
)

@plugin_function_logger("SimpleChatPlugin")
# bac-check: ignore - add_group_member_for_current_user validates the current user's group role before mutation.
@kernel_function(description="Add a user directly to a group as the current user. user_identifier can be an email, user principal name, or user ID. If group_id is omitted, the active group is used.")
# bac-check: ignore - add_group_member_for_current_user validates the current user's group role before mutation; user_id only names the member to add, as the REST members route accepts.

Check warning on line 479 in application/single_app/semantic_kernel_plugins/simplechat_plugin.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.
@kernel_function(description="Add a user directly to a group as the current user. user_identifier can be an email, user principal name, or user ID. When you know the user's object ID, pass it as user_id with their email or display_name to add them without a directory lookup. If group_id is omitted, the active group is used.")

Check warning on line 480 in application/single_app/semantic_kernel_plugins/simplechat_plugin.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains AI, plugin, agent, or workspace boundary marker. Recommendation%3A Check whether prompts, chat history, uploaded documents, embeddings, citations, settings, or identity can cross a new boundary.

Check warning on line 480 in application/single_app/semantic_kernel_plugins/simplechat_plugin.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.

Check warning on line 480 in application/single_app/semantic_kernel_plugins/simplechat_plugin.py

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Moderate - Changed line contains obfuscation, dynamic loading, or hidden payload marker. Recommendation%3A Confirm the changed code is not hiding behavior, decoding payloads, or bypassing normal review.
def add_user_to_group(
self,
user_identifier: str = "",
group_id: str = "",
role: str = "user",
display_name: str = "",
email: str = "",
user_id: str = "",
) -> dict:
return self._execute_operation(
"add_group_member",
lambda: _with_agent_group_summary(add_group_member_for_current_user(
group_id=group_id,
user_id=user_id,
user_identifier=user_identifier,
email=email,
display_name=display_name,
Expand Down
Loading
Loading