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
4 changes: 4 additions & 0 deletions application/single_app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,10 @@
print("Setting up Application Insights logging...")
setup_appinsights_logging(settings)
logging.basicConfig(level=logging.DEBUG)
# basicConfig above is a no-op once Azure Monitor owns the root logger,
# and that same root handler stops Flask attaching its stderr handler,
# so unhandled tracebacks would otherwise never reach the container log.

Check warning on line 326 in application/single_app/app.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.
ensure_console_error_logging(app.logger)
ensure_default_global_agent_exists()

start_background_tasks()
Expand Down
2 changes: 1 addition & 1 deletion application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
EXECUTOR_TYPE = 'thread'
EXECUTOR_MAX_WORKERS = 30
SESSION_TYPE = 'filesystem'
VERSION = "0.260.018"
VERSION = "0.260.019"
IS_DEVELOPMENT = is_development_env_enabled()

SESSION_COOKIE_SAMESITE = os.getenv('SESSION_COOKIE_SAMESITE', 'Lax')
Expand Down
54 changes: 54 additions & 0 deletions application/single_app/functions_appinsights.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import os
import re
import sys
import threading
from datetime import date, datetime
from typing import Any, Dict, Optional, Tuple
Expand All @@ -14,6 +15,8 @@
_appinsights_logger = None
_azure_monitor_configured = False
_logging_settings_load_state = threading.local()
CONSOLE_ERROR_HANDLER_ATTRIBUTE = "_simplechat_console_error_handler"
CONSOLE_ERROR_LOG_FORMAT = "[%(asctime)s] %(levelname)s in %(name)s: %(message)s"
REDACTED_LOG_VALUE = "***REDACTED***"
MAX_LOG_STRING_LENGTH = 8192
SENSITIVE_LOG_KEY_FRAGMENTS = (
Expand Down Expand Up @@ -629,3 +632,54 @@
print(f"[AZURE_MONITOR] Failed to setup Application Insights: {e}")
_azure_monitor_configured = False
# Don't re-raise the exception, just continue without Application Insights


def ensure_console_error_logging(logger):
"""
Guarantee that a logger writes ERROR records to stderr.

Flask only attaches its own stderr handler when ``logging.Logger`` finds no
level handler anywhere up the hierarchy. ``configure_azure_monitor`` attaches
a handler to the root logger, which also turns ``logging.basicConfig`` into a
no-op, so unhandled request tracebacks are delivered to Application Insights

Check warning on line 644 in application/single_app/functions_appinsights.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.
and never printed. On App Service that leaves nothing but the access-log line
in the container log, which makes 500s effectively invisible.

The handler is attached to the supplied logger rather than to root, and is
pinned at ERROR, so library DEBUG output is never echoed to the console.

Args:
logger (logging.Logger): Logger to attach the stderr handler to,
typically ``app.logger``.

Returns:
logging.Handler: The console handler now attached to the logger, or
``None`` when no logger was supplied.

Raises:
None: Handler setup failures are reported and swallowed so that logging
configuration can never prevent the application from starting.
"""
if logger is None:
return None

try:

Check warning on line 666 in application/single_app/functions_appinsights.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.
for existing_handler in logger.handlers:
if getattr(existing_handler, CONSOLE_ERROR_HANDLER_ATTRIBUTE, False):

Check warning on line 668 in application/single_app/functions_appinsights.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.
return existing_handler

console_handler = logging.StreamHandler(sys.stderr)
console_handler.setLevel(logging.ERROR)
console_handler.setFormatter(logging.Formatter(CONSOLE_ERROR_LOG_FORMAT))
setattr(console_handler, CONSOLE_ERROR_HANDLER_ATTRIBUTE, True)

Check warning on line 674 in application/single_app/functions_appinsights.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.
logger.addHandler(console_handler)

# A logger left at NOTSET defers to the root level, which Azure Monitor
# may have raised above ERROR, so pin it low enough to emit tracebacks.

Check warning on line 678 in application/single_app/functions_appinsights.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 logger.level == logging.NOTSET or logger.level > logging.ERROR:
logger.setLevel(logging.ERROR)

return console_handler
except Exception as handler_error:

Check warning on line 683 in application/single_app/functions_appinsights.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.
print(f"[AZURE_MONITOR] Failed to attach console error handler: {handler_error}")
return None
2 changes: 0 additions & 2 deletions application/single_app/static/js/admin/admin_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ let imageSelected = window.imageSelected || [];
let imageAll = window.imageAll || [];

let classificationCategories = window.classificationCategories || [];
let enableDocumentClassification = window.enableDocumentClassification || false;

let externalLinks = window.externalLinks || [];
let enableExternalLinks = window.enableExternalLinks || false;
let externalLinksMenuName = window.externalLinksMenuName || 'External Links';
let agentsPagePromotedPopularAgents = Array.isArray(window.agentsPagePromotedPopularAgents)
? window.agentsPagePromotedPopularAgents
Expand Down
5 changes: 5 additions & 0 deletions application/single_app/templates/admin/_panes/actions.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<div class="tab-pane fade{% if admin_landing_tab == 'actions' %} show active{% endif %}" id="actions" role="tabpanel" aria-labelledby="actions-tab">
{# These live here, not in the Agents pane, because sibling

Check warning on line 2 in application/single_app/templates/admin/_panes/actions.html

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.
{% include %} panes each render in their own scope: a value
set in one pane is not visible to the next one. #}
{% set analyze_capability = settings.document_action_capabilities.analyze %}
{% set comparison_capability = settings.document_action_capabilities.comparison %}
<div class="card p-3 mb-4" id="document-action-capabilities-card">
<div class="d-flex flex-column flex-lg-row justify-content-between align-items-lg-center gap-3 mb-3">
<div>
Expand Down
2 changes: 0 additions & 2 deletions application/single_app/templates/admin/_panes/agents.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
<strong>Note:</strong> All changes to global agents and actions require a restart of the web app to take effect.
</div>

{% set analyze_capability = settings.document_action_capabilities.analyze %}
{% set comparison_capability = settings.document_action_capabilities.comparison %}
<div class="card p-3 mb-4" id="agents-configuration">
<h5 class="card-title">
<i class="bi bi-robot me-2"></i>Agents Configuration
Expand Down
12 changes: 6 additions & 6 deletions application/single_app/templates/admin/_panes/cosmos.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ <h5 class="mb-1">
<button type="button" class="btn btn-outline-secondary btn-sm" id="document-access-index-refresh-btn">
<i class="bi bi-arrow-clockwise me-1" aria-hidden="true"></i>Refresh Status
</button>
{% if enable_dai_debug %}
{% if settings.enable_dai_debug %}
<button type="button" class="btn btn-outline-primary btn-sm" id="document-access-index-run-batch-btn">
<i class="bi bi-play-circle me-1" aria-hidden="true"></i>Run One Backfill Batch
</button>
Expand All @@ -27,7 +27,7 @@ <h5 class="mb-1">
<div class="alert alert-info small mb-3">
<i class="bi bi-info-circle me-2" aria-hidden="true"></i>
Document access projection maintenance is automatic. The background scheduler repairs fail-open projection records first, then runs bounded backfill batches repeatedly while work remains. Production read metrics below show DAI-served reads, Redis cache hits, source fallbacks, RU, and latency without requiring shadow validation.
{% if enable_dai_debug %}Debug controls and shadow validation diagnostics are visible because <code>enable_dai_debug</code> is enabled in app settings.{% endif %}
{% if settings.enable_dai_debug %}Debug controls and shadow validation diagnostics are visible because <code>enable_dai_debug</code> is enabled in app settings.{% endif %}
</div>

<div id="document-access-index-message" class="alert alert-info d-none" role="status" aria-live="polite"></div>
Expand Down Expand Up @@ -57,7 +57,7 @@ <h5 class="mb-1">
<span class="badge text-bg-secondary" id="document-access-index-cache-status">Not loaded</span>
</div>
</div>
{% if enable_dai_debug %}
{% if settings.enable_dai_debug %}
<div class="col-md-6 col-xl-3">
<div class="border rounded p-2 h-100">
<div class="small text-muted">Shadow Validation</div>
Expand Down Expand Up @@ -91,7 +91,7 @@ <h5 class="mb-1">
</div>
</div>

{% if enable_dai_debug %}
{% if settings.enable_dai_debug %}
<div class="border rounded p-3 mb-3" data-testid="document-access-index-debug-controls">
<h6 class="mb-3">Automatic Maintenance and Diagnostics</h6>
<div class="row g-3 align-items-start">
Expand Down Expand Up @@ -327,7 +327,7 @@ <h6 class="mb-3">Default Read Path</h6>
Production read metrics are lightweight in-process counters for the current app worker. Application Insights logs remain the durable fleet-wide source for fallback warnings and query failures.
</div>
</div>
{% if enable_dai_debug %}
{% if settings.enable_dai_debug %}
<div class="col-md-6 col-xl-3">
<div class="border rounded p-2 h-100">
<div class="small text-muted">Last Shadow Result</div>
Expand Down Expand Up @@ -653,7 +653,7 @@ <h5 class="modal-title" id="staleCacheCleanupApplyModalLabel">
</div>
</div>

{% if enable_dai_debug %}
{% if settings.enable_dai_debug %}
<div class="modal fade" id="documentAccessIndexResetModal" tabindex="-1" aria-labelledby="documentAccessIndexResetModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
Expand Down
2 changes: 0 additions & 2 deletions application/single_app/templates/admin_settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -2292,15 +2292,13 @@ <h5 class="modal-title" id="userAgreementPreviewModalLabel">
if (!Array.isArray(window.classificationCategories)) {
window.classificationCategories = [];
}
window.enableDocumentClassification = "{{ enable_document_classification }}";

// *** NEW: External Links Data ***
window.externalLinks = {{ settings.external_links|default([], true)|tojson(indent=None)|safe }};
// Ensure it's always an array
if (!Array.isArray(window.externalLinks)) {
window.externalLinks = [];
}
window.enableExternalLinks = "{{ enable_external_links }}";
window.externalLinksMenuName = "{{ settings.external_links_menu_name or 'External Links' }}";
window.externalLinksForceMenu = "{{ settings.external_links_force_menu }}";
window.agentsPagePromotedPopularAgents = {{ settings.agents_page_promoted_popular_agents | default([], true) | tojson(indent=None) }};
Expand Down
Loading
Loading