SIENTIAPDE-1646

Simplify bandit nosec comments and mock metrics_controller with real spe

- drift.py/simple_metrics.py: move nosec rationale to a code comment above
  the query instead of an inline suppression comment, keeping bandit happy
  with a plain `# nosec`
- tests: replace bare `MagicMock()` with `MagicMock(spec=MetricsController)`
  for metrics_controller across activities/repository tests so mocks fail
  fast on attribute typos instead of silently accepting any call
This commit is contained in:
2026-09-25 10:57:46 -03:00
parent 4c51e7c2b3
commit 00b6382a88
9 changed files with 29 additions and 20 deletions

View File

@@ -37,6 +37,7 @@ class Drift:
model_config = input_data['model_config']
target_name = model_config['target']
# Built from internal Temporal workflow config, not user input (bandit B608).
gathering_query = f"""
SELECT *
FROM "{input_data['schema']}"."{input_data['source_table_name']}"
@@ -44,7 +45,7 @@ class Drift:
model_id = '{input_data['model_id']}' AND
timestamp > NOW() - INTERVAL '{input_data['interval']} minutes'
ORDER BY timestamp ASC
""" # nosec B608 - values come from internal Temporal workflow config, not user input
""" # nosec
target_data_handler = workflow.start_activity_method(
Activities.load_custom_query,

View File

@@ -32,6 +32,7 @@ class SimpleMetrics:
model_config = input_data['model_config']
target_name = model_config['target']
# Built from internal Temporal workflow config, not user input (bandit B608).
query = f"""
select p."timestamp", p.prediction, ld.value as "target"
from "{input_data['schema']}"."{input_data['predictions_table_name']}" p
@@ -45,7 +46,7 @@ class SimpleMetrics:
p."timestamp" >= NOW() - INTERVAL '{interval_minutes} minutes'
order by
p."timestamp" desc;
""" # nosec B608 - values come from internal Temporal workflow config, not user input
""" # nosec
target_data = await workflow.execute_activity_method(
Activities.load_custom_query,

View File

@@ -2,6 +2,7 @@ from unittest.mock import ANY, MagicMock, call, patch
from pytest import fixture
from sientia_do.notifications.models import NotificationLevel
from sientia_do.observability.metrics_controller import MetricsController
from laborious.activities.api import API, PI_WEB_API_PREDICTION_ERROR_CONFIDENCE
@@ -70,7 +71,7 @@ def test_get_pi_web_api_core_labels_without_operation_type(mock_pi_web_api_clien
auth_token='test_token',
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
with patch.object(
SientiaMonitoring,
@@ -104,7 +105,7 @@ def test_get_pi_web_api_core_labels_with_operation_type(mock_pi_web_api_client):
auth_token='test_token',
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
with patch.object(
SientiaMonitoring,
@@ -131,7 +132,7 @@ def test__init__():
auth_token='test_token',
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
assert api.pi_web_api_client is not None
@@ -152,7 +153,7 @@ def api(mock_pi_web_api_client):
auth_token='test_token',
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
api_instance.send_notification = MagicMock()
api_instance.info = MagicMock()

View File

@@ -3,6 +3,7 @@ from unittest.mock import ANY, MagicMock, call, patch
from pandas import DataFrame
from pytest import fixture
from sientia_do.notifications.models import NotificationLevel
from sientia_do.observability.metrics_controller import MetricsController
from sientia_do.observability.sientia_monitoring import SientiaMonitoring
from laborious.activities.gates import Gates
@@ -38,7 +39,7 @@ def gates_activity():
gates = Gates(
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
gates.error = MagicMock()
gates.debug = MagicMock()
@@ -985,7 +986,7 @@ def test_close_disposes_minio_repository(mock_shutdown):
minio_repository=minio,
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
gates.close()
minio.close.assert_called_once()
@@ -1000,7 +1001,7 @@ def test_close_without_minio_repository(mock_shutdown):
minio_repository=None,
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
gates.close()
mock_shutdown.assert_called_once_with(gates)

View File

@@ -5,6 +5,7 @@ import numpy as np
import pandas as pd
from pytest import fixture, raises
from sientia_do.notifications.models import NotificationLevel
from sientia_do.observability.metrics_controller import MetricsController
from sientia_do.temporal.constants import DATETIME_FORMAT_WITH_TZ
from laborious.activities.mlflow import MLFlow
@@ -22,7 +23,7 @@ def _passthrough_from_dict():
def test___init__(mock_minio_repository):
logger = MagicMock()
notification_handler = MagicMock()
metrics_controller = MagicMock()
metrics_controller = MagicMock(spec=MetricsController)
mlflow_repo = MagicMock()
plugin_store = MagicMock()
@@ -63,7 +64,7 @@ def test___init__(mock_minio_repository):
def mlflow(mock_minio_repository):
logger = MagicMock()
notification_handler = MagicMock()
metrics_controller = MagicMock()
metrics_controller = MagicMock(spec=MetricsController)
mlflow_repo = MagicMock()
plugin_store = MagicMock()

View File

@@ -3,6 +3,7 @@ from unittest.mock import ANY, MagicMock, patch
from pandas import DataFrame, Timestamp
from pytest import fixture, raises
from sientia_do.notifications.models import NotificationLevel
from sientia_do.observability.metrics_controller import MetricsController
from sientia_do.temporal.constants import DATETIME_FORMAT_WITH_TZ
from sientia_model.analytics.drift_analysis import DriftInsufficientDataError
@@ -14,7 +15,7 @@ def model_metrics_activity():
model_metrics = ModelMetrics(
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
model_metrics.error = MagicMock()
model_metrics.debug = MagicMock()

View File

@@ -4,6 +4,7 @@ import pytest
from pandas import DataFrame
from pytest import mark
from sientia_do.notifications.models import NotificationLevel
from sientia_do.observability.metrics_controller import MetricsController
from laborious.activities.opc import (
OPC,
@@ -32,7 +33,7 @@ def test__init__():
opc_servers=servers,
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
assert opc.opc_servers == servers
@@ -43,7 +44,7 @@ def test__init__():
@patch('laborious.activities.opc.OPC.send_notification')
def test_init_opc(mock_send_notification, mock_opc_repository):
mock_logger = MagicMock()
mock_metrics_controller = MagicMock()
mock_metrics_controller = MagicMock(spec=MetricsController)
server1 = MagicMock(
connect=MagicMock(return_value=(True, {})), write_data=MagicMock(return_value=(True, {}))
)
@@ -192,7 +193,7 @@ def opc(mock_opc_repository):
opc_servers=servers,
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
opc.init_opc()
opc.send_notification = MagicMock()

View File

@@ -4,6 +4,7 @@ from unittest.mock import ANY, MagicMock, patch
from pytest import fixture, raises
from sientia_do.notifications.models import NotificationLevel
from sientia_do.observability.metrics_controller import MetricsController
from sientia_do.observability.sientia_monitoring import SientiaMonitoring
from sientia_do.temporal.activities.postgres_sync import Postgres
@@ -52,7 +53,7 @@ def storage(mock_minio_repository):
minio_repository=mock_minio_repository.return_value,
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
@@ -60,7 +61,7 @@ def storage(mock_minio_repository):
def test___init___not_hasattr(mock_minio_repository):
logger = MagicMock()
notification_handler = MagicMock()
metrics_controller = MagicMock()
metrics_controller = MagicMock(spec=MetricsController)
minio_repo = mock_minio_repository.return_value
storage = Storage(
host='localhost',
@@ -87,7 +88,7 @@ def test___init___none_minio_repository(mock_minio_repository, storage):
storage.minio_repository = None
logger = MagicMock()
notification_handler = MagicMock()
metrics_controller = MagicMock()
metrics_controller = MagicMock(spec=MetricsController)
storage.__init__(
host='localhost',
port=5432,
@@ -121,7 +122,7 @@ def test___init___done_repository(mock_minio_repository, storage):
minio_repository=mock_minio_repository.return_value,
logger=MagicMock(),
notification_handler=MagicMock(),
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
mock_minio_repository.assert_not_called()
assert storage.minio_repository is not None

View File

@@ -9,6 +9,7 @@ import pytest
from asyncua.crypto import security_policies
from asyncua.ua.uaerrors import BadNodeIdUnknown, BadSessionIdInvalid
from sientia_do.notifications.models import NotificationLevel
from sientia_do.observability.metrics_controller import MetricsController
from laborious import metrics
from laborious.utils.repository.opc_repository import (
@@ -39,7 +40,7 @@ def opc_repository(mock_logger):
cert_path='/path/to/cert.pem',
private_key_path='/path/to/key.pem',
server_cert_path='/path/to/server_cert.pem',
metrics_controller=MagicMock(),
metrics_controller=MagicMock(spec=MetricsController),
)
repository.disconnection_interval = 0.1
repository.send_notification = MagicMock()