Skip to content

Commit 3d64e25

Browse files
committed
add keyvault and dynamic addsetting ui
1 parent 7114bac commit 3d64e25

27 files changed

+1231
-241
lines changed

application/single_app/agent_logging_chat_completion.py

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,6 @@ async def invoke(self, *args, **kwargs):
144144
}
145145
)
146146

147-
log_event("[Logging Agent Request] Agent invoke started",
148-
extra={
149-
"agent": self.name,
150-
"prompt_preview": [m.content[:30] for m in args[0]] if args else None
151-
},
152-
level=logging.DEBUG)
153-
154147
# Store user question context for better tool detection
155148
if args and args[0] and hasattr(args[0][-1], 'content'):
156149
self._user_question = args[0][-1].content
@@ -163,12 +156,14 @@ async def invoke(self, *args, **kwargs):
163156
initial_message_count = len(args[0]) if args and args[0] else 0
164157
result = super().invoke(*args, **kwargs)
165158

166-
log_event("[Logging Agent Request] Result received",
167-
extra={
168-
"agent": self.name,
169-
"result_type": type(result).__name__
170-
},
171-
level=logging.DEBUG)
159+
log_event(
160+
"[Logging Agent Request] Result received",
161+
extra={
162+
"agent": self.name,
163+
"result_type": type(result).__name__
164+
},
165+
level=logging.DEBUG
166+
)
172167

173168
if hasattr(result, "__aiter__"):
174169
# Streaming/async generator response
@@ -180,13 +175,15 @@ async def invoke(self, *args, **kwargs):
180175
# Regular coroutine response
181176
response = await result
182177

183-
log_event("[Logging Agent Request] Response received",
184-
extra={
185-
"agent": self.name,
186-
"response_type": type(response).__name__,
187-
"response_preview": str(response)[:100] if response else None
188-
},
189-
level=logging.DEBUG)
178+
log_event(
179+
"[Logging Agent Request] Response received",
180+
extra={
181+
"agent": self.name,
182+
"response_type": type(response).__name__,
183+
"response_preview": str(response)[:100] if response else None
184+
},
185+
level=logging.DEBUG
186+
)
190187

191188
# Store the response for analysis
192189
self._last_response = response

application/single_app/app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105

106106
from route_external_health import *
107107

108+
#TODO: Remove this after speaking with Paul
108109
configure_azure_monitor()
109110

110111
# =================== Session Configuration ===================

application/single_app/functions_appinsights.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def log_event(
7171
exc_info_to_use = True
7272

7373
# Format message with extra properties for structured logging
74+
print(f"[Log] {message} -- {extra}") # Debug print to console
7475
if extra:
7576
# For modern Azure Monitor, extra properties are automatically captured
7677
logger.log(

application/single_app/functions_global_actions.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
import traceback
1212
from datetime import datetime
1313
from config import cosmos_global_actions_container
14+
from functions_keyvault import keyvault_plugin_save_helper, keyvault_plugin_get_helper, keyvault_plugin_delete_helper
1415

15-
def get_global_actions():
16+
def get_global_actions(return_actual_key=False):
1617
"""
1718
Get all global actions.
1819
@@ -24,7 +25,8 @@ def get_global_actions():
2425
query="SELECT * FROM c",
2526
enable_cross_partition_query=True
2627
))
27-
28+
# Resolve Key Vault references for each action
29+
actions = [keyvault_plugin_get_helper(a, scope_value=a.get('id'), scope="global", return_actual_key=return_actual_key) for a in actions]
2830
return actions
2931

3032
except Exception as e:
@@ -33,7 +35,7 @@ def get_global_actions():
3335
return []
3436

3537

36-
def get_global_action(action_id):
38+
def get_global_action(action_id, return_actual_key=False):
3739
"""
3840
Get a specific global action by ID.
3941
@@ -48,7 +50,8 @@ def get_global_action(action_id):
4850
item=action_id,
4951
partition_key=action_id
5052
)
51-
53+
# Resolve Key Vault references
54+
action = keyvault_plugin_get_helper(action, scope_value=action_id, scope="global", return_actual_key=return_actual_key)
5255
print(f"✅ Found global action: {action_id}")
5356
return action
5457

@@ -71,16 +74,14 @@ def save_global_action(action_data):
7174
# Ensure required fields
7275
if 'id' not in action_data:
7376
action_data['id'] = str(uuid.uuid4())
74-
7577
# Add metadata
7678
action_data['is_global'] = True
7779
action_data['created_at'] = datetime.utcnow().isoformat()
7880
action_data['updated_at'] = datetime.utcnow().isoformat()
79-
8081
print(f"💾 Saving global action: {action_data.get('name', 'Unknown')}")
81-
82+
# Store secrets in Key Vault before upsert
83+
action_data = keyvault_plugin_save_helper(action_data, scope_value=action_data.get('id'), scope="global")
8284
result = cosmos_global_actions_container.upsert_item(body=action_data)
83-
8485
print(f"✅ Global action saved successfully: {result['id']}")
8586
return result
8687

@@ -102,12 +103,14 @@ def delete_global_action(action_id):
102103
"""
103104
try:
104105
print(f"🗑️ Deleting global action: {action_id}")
105-
106+
# Delete secrets from Key Vault before deleting the action
107+
action = get_global_action(action_id)
108+
if action:
109+
keyvault_plugin_delete_helper(action, scope_value=action_id, scope="global")
106110
cosmos_global_actions_container.delete_item(
107111
item=action_id,
108112
partition_key=action_id
109113
)
110-
111114
print(f"✅ Global action deleted successfully: {action_id}")
112115
return True
113116

application/single_app/functions_keyvault.py

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import re
44
import logging
5+
from functions_appinsights import log_event
56
from config import *
67
from functions_authentication import *
78
from functions_settings import *
@@ -20,10 +21,6 @@
2021
"""
2122

2223
supported_sources = [
23-
'model_deployment',
24-
'speech_service',
25-
'storage_account',
26-
'cognitive_service',
2724
'action',
2825
'action-addset',
2926
'agent',
@@ -40,6 +37,7 @@
4037
'key',
4138
'servicePrincipal',
4239
'basic',
40+
'username_password',
4341
'connection_string'
4442
]
4543

@@ -85,13 +83,14 @@ def retrieve_secret_from_keyvault_by_full_name(full_secret_name):
8583
settings = get_settings()
8684
enable_key_vault_secret_storage = settings.get("enable_key_vault_secret_storage", False)
8785
if not enable_key_vault_secret_storage:
88-
logging.error(f"Key Vault secret storage is not enabled.")
89-
raise Exception("Key Vault secret storage is not enabled.")
86+
return value
9087

9188
key_vault_name = settings.get("key_vault_name", None)
9289
if not key_vault_name:
93-
logging.error(f"Key Vault name is not configured.")
94-
raise Exception("Key Vault name is not configured.")
90+
return value
91+
92+
if not validate_secret_name_dynamic(full_secret_name):
93+
return value
9594

9695
try:
9796
key_vault_url = f"https://{key_vault_name}{KEY_VAULT_DOMAIN}"
@@ -101,7 +100,9 @@ def retrieve_secret_from_keyvault_by_full_name(full_secret_name):
101100
print(f"Secret '{full_secret_name}' retrieved successfully from Key Vault.")
102101
return retrieved_secret.value
103102
except Exception as e:
104-
raise Exception(f"Failed to retrieve secret '{full_secret_name}' from Key Vault: {str(e)}") from e
103+
logging.error(f"Failed to retrieve secret '{full_secret_name}' from Key Vault: {str(e)}")
104+
return value
105+
105106

106107
def store_secret_in_key_vault(secret_name, secret_value, scope_value, source="global", scope="global"):
107108
"""
@@ -122,13 +123,13 @@ def store_secret_in_key_vault(secret_name, secret_value, scope_value, source="gl
122123
settings = get_settings()
123124
enable_key_vault_secret_storage = settings.get("enable_key_vault_secret_storage", False)
124125
if not enable_key_vault_secret_storage:
125-
logging.error(f"Key Vault secret storage is not enabled.")
126-
raise Exception("Key Vault secret storage is not enabled.")
126+
logging.warn(f"Key Vault secret storage is not enabled.")
127+
return secret_value
127128

128129
key_vault_name = settings.get("key_vault_name", None)
129130
if not key_vault_name:
130-
logging.error(f"Key Vault name is not configured.")
131-
raise Exception("Key Vault name is not configured.")
131+
logging.warn(f"Key Vault name is not configured.")
132+
return secret_value
132133

133134
if source not in supported_sources:
134135
logging.error(f"Source '{source}' is not supported. Supported sources: {supported_sources}")
@@ -148,7 +149,7 @@ def store_secret_in_key_vault(secret_name, secret_value, scope_value, source="gl
148149
return full_secret_name
149150
except Exception as e:
150151
logging.error(f"Failed to store secret '{full_secret_name}' in Key Vault: {str(e)}")
151-
raise Exception(f"Failed to store secret '{full_secret_name}' in Key Vault: {str(e)}") from e
152+
return secret_value
152153

153154
def build_full_secret_name(secret_name, scope_value, source, scope):
154155
"""
@@ -267,13 +268,13 @@ def keyvault_agent_get_helper(agent_dict, scope_value, scope="global", return_ac
267268
if validate_secret_name_dynamic(value):
268269
try:
269270
if return_actual_key:
270-
actual_key = retrieve_secret_from_key_vault(value)
271+
actual_key = retrieve_secret_from_key_vault_by_full_name(value)
271272
updated[key] = actual_key
272273
else:
273274
updated[key] = ui_trigger_word
274275
except Exception as e:
275276
logging.error(f"Failed to retrieve agent key '{key}' from Key Vault: {e}")
276-
raise Exception(f"Failed to retrieve agent key '{key}' from Key Vault: {e}")
277+
return updated
277278
return updated
278279

279280
def keyvault_plugin_save_helper(plugin_dict, scope_value, scope="global"):
@@ -375,8 +376,8 @@ def keyvault_plugin_get_helper(plugin_dict, scope_value, scope="global", return_
375376
new_auth['key'] = ui_trigger_word
376377
updated['auth'] = new_auth
377378
except Exception as e:
378-
logging.error(f"Failed to retrieve plugin key from Key Vault: {e}")
379-
raise Exception(f"Failed to retrieve plugin key from Key Vault: {e}")
379+
logging.error(f"Failed to retrieve action key from Key Vault: {e}")
380+
raise Exception(f"Failed to retrieve action key from Key Vault: {e}")
380381

381382
additional_fields = updated.get('additionalFields', {})
382383
if isinstance(additional_fields, dict):
@@ -393,8 +394,8 @@ def keyvault_plugin_get_helper(plugin_dict, scope_value, scope="global", return_
393394
else:
394395
new_additional_fields[k] = ui_trigger_word
395396
except Exception as e:
396-
logging.error(f"Failed to retrieve plugin additionalField secret '{k}' from Key Vault: {e}")
397-
raise Exception(f"Failed to retrieve plugin additionalField secret '{k}' from Key Vault: {e}")
397+
logging.error(f"Failed to retrieve action additionalField secret '{k}' from Key Vault: {e}")
398+
raise Exception(f"Failed to retrieve action additionalField secret '{k}' from Key Vault: {e}")
398399
updated['additionalFields'] = new_additional_fields
399400
return updated
400401
# Helper to delete plugin secrets from Key Vault
@@ -413,12 +414,13 @@ def keyvault_plugin_delete_helper(plugin_dict, scope_value, scope="global"):
413414
Raises:
414415
"""
415416
if scope not in supported_scopes:
416-
logging.error(f"Scope '{scope}' is not supported. Supported scopes: {supported_scopes}")
417+
log_event(f"Scope '{scope}' is not supported. Supported scopes: {supported_scopes}", level="WARNING")
417418
raise ValueError(f"Scope '{scope}' is not supported. Supported scopes: {supported_scopes}")
418419
settings = get_settings()
419420
enable_key_vault_secret_storage = settings.get("enable_key_vault_secret_storage", False)
420421
key_vault_name = settings.get("key_vault_name", None)
421422
if not enable_key_vault_secret_storage or not key_vault_name:
423+
log_event(f"Key Vault secret storage is not enabled or key vault name is missing.", level="WARNING")
422424
return plugin_dict
423425
source = "action"
424426
plugin_name = plugin_dict.get('name', 'plugin')
@@ -429,11 +431,12 @@ def keyvault_plugin_delete_helper(plugin_dict, scope_value, scope="global"):
429431
if validate_secret_name_dynamic(secret_name):
430432
try:
431433
key_vault_url = f"https://{key_vault_name}{KEY_VAULT_DOMAIN}"
434+
log_event(f"Deleting action secret '{secret_name}' for action '{plugin_name}' for '{scope}' '{scope_value}'", level="INFO")
432435
client = SecretClient(vault_url=key_vault_url, credential=get_keyvault_credential())
433436
client.begin_delete_secret(secret_name)
434437
except Exception as e:
435-
logging.error(f"Error deleting plugin secret '{secret_name}' for plugin '{plugin_name}': {e}")
436-
raise Exception(f"Error deleting plugin secret '{secret_name}' for plugin '{plugin_name}': {e}")
438+
logging.error(f"Error deleting action secret '{secret_name}' for action '{plugin_name}': {e}")
439+
raise Exception(f"Error deleting action secret '{secret_name}' for action '{plugin_name}': {e}")
437440

438441
additional_fields = plugin_dict.get('additionalFields', {})
439442
if isinstance(additional_fields, dict):
@@ -445,11 +448,12 @@ def keyvault_plugin_delete_helper(plugin_dict, scope_value, scope="global"):
445448
try:
446449
keyvault_secret_name = build_full_secret_name(akv_key, scope_value, addset_source, scope)
447450
key_vault_url = f"https://{key_vault_name}{KEY_VAULT_DOMAIN}"
451+
log_event(f"Deleting action additionalField secret '{k}' for action '{plugin_name}' for '{scope}' '{scope_value}'", level="INFO")
448452
client = SecretClient(vault_url=key_vault_url, credential=get_keyvault_credential())
449453
client.begin_delete_secret(keyvault_secret_name)
450454
except Exception as e:
451-
logging.error(f"Error deleting plugin additionalField secret '{k}' for plugin '{plugin_name}': {e}")
452-
raise Exception(f"Error deleting plugin additionalField secret '{k}' for plugin '{plugin_name}': {e}")
455+
logging.error(f"Error deleting action additionalField secret '{k}' for action '{plugin_name}': {e}")
456+
raise Exception(f"Error deleting action additionalField secret '{k}' for action '{plugin_name}': {e}")
453457
return plugin_dict
454458

455459
# Helper to delete agent secrets from Key Vault
@@ -482,6 +486,7 @@ def keyvault_agent_delete_helper(agent_dict, scope_value, scope="global"):
482486
if validate_secret_name_dynamic(secret_name):
483487
try:
484488
key_vault_url = f"https://{key_vault_name}{KEY_VAULT_DOMAIN}"
489+
log_event(f"Deleting agent secret '{secret_name}' for agent '{agent_name}' for '{scope}' '{scope_value}'", level="INFO")
485490
client = SecretClient(vault_url=key_vault_url, credential=get_keyvault_credential())
486491
client.begin_delete_secret(secret_name)
487492
except Exception as e:

0 commit comments

Comments
 (0)