"""Non-secret exposure diagnostics preferences, independent of NPM ACL policy.""" from sqlalchemy.exc import SQLAlchemyError from sqlmodel import Session, select from ..core.time import utc_now from ..db import session as database from ..db.models import AppSetting from ..schemas.exposure_preferences import ExposurePreferences, ExposurePreferencesUpdate from .audit_logger import log_event EXPOSURE_PREFERENCES_KEY = "exposure:preferences" def get_exposure_preferences(session: Session) -> ExposurePreferences: row = session.get(AppSetting, EXPOSURE_PREFERENCES_KEY) value = row.value_json if row and isinstance(row.value_json, dict) else {} # Only an explicit stored boolean false disables diagnostics. Corrupt or # missing configuration keeps the secure default without crashing reads. return ExposurePreferences(nginxAccessListChecksEnabled=value.get("nginxAccessListChecksEnabled") is not False) def runtime_nginx_access_list_checks_enabled() -> bool: """Read the same persisted flag for connectors running outside API routes.""" try: with Session(database.engine) as session: return get_exposure_preferences(session).nginxAccessListChecksEnabled except SQLAlchemyError: return True def update_exposure_preferences(session: Session, payload: ExposurePreferencesUpdate, *, identity: str) -> ExposurePreferences: before = get_exposure_preferences(session) after = ExposurePreferences(**payload.model_dump()) if before == after: return after row = session.get(AppSetting, EXPOSURE_PREFERENCES_KEY) or AppSetting(key=EXPOSURE_PREFERENCES_KEY) row.value_json = after.model_dump() row.is_secret = False row.updated_at = utc_now() session.add(row) # Derived persistent snapshots must not show warnings from the previous # preference. Their signatures also include the effective boolean. for cached in session.exec(select(AppSetting)).all(): if cached.key in {"network_exposure:cache", "safety_center:dashboard_cache"} or cached.key.startswith("ai_security:review_cache:"): session.delete(cached) log_event( session, source="manual", identity=identity, action_id="settings.exposure.update", target=EXPOSURE_PREFERENCES_KEY, target_type="setting", risk="low", policy_decision="allowed", reason="Administrator updated NPM access-list diagnostics preference", result="success", before_state=before.model_dump(), after_state=after.model_dump(), ) return after