From 255b8a08c2269d7ea5e08132a626d8bcf1f22bdf Mon Sep 17 00:00:00 2001 From: mmolenda Date: Thu, 25 Jun 2026 16:02:48 +0200 Subject: [PATCH] Enabling markeplaces related alerts --- README.md | 7 ++++--- pyrightconfig.json | 5 +++++ tests/test_helpers.py | 17 +++++++++++++++-- verity471/helpers/alerts.py | 8 ++++---- 4 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 pyrightconfig.json diff --git a/README.md b/README.md index 090a234..bcf84c9 100644 --- a/README.md +++ b/README.md @@ -224,8 +224,9 @@ fetched target object — a report, forum post, credential, indicator, or any ot When a target cannot be fetched (no link, no known SDK route, forbidden, or an unexpected error), the alert is still returned by default with `target=None` and a `status` explaining why, so nothing -is silently lost. Pass `skip_missing_targets=True` to omit such alerts instead. Marketplace alerts -are always skipped silently. +is silently lost. Pass `skip_missing_targets=True` to omit such alerts instead. Marketplace hits +have no SDK route yet, so they come back as bare alerts with `status=UNRESOLVABLE` (or are omitted +when `skip_missing_targets=True`), the same as any other unresolvable target. ```python from verity471.helpers import fetch_alert_targets, AlertTarget, AlertTargetStatus @@ -238,7 +239,7 @@ from verity471.helpers import fetch_alert_targets, AlertTarget, AlertTargetStatu | `alerts_response` | `StreamingAlertsResponse` | *(required)* | The page returned by `AlertsApi.get_alerts_stream()`. | | `api_client` | `ApiClient` | *(required)* | An active `ApiClient` instance (must share credentials with the alerts call). | | `raise_on_error` | `bool` | `False` | When `True`, re-raise unexpected errors (and the missing-link error) instead of recording them on the result. | -| `skip_missing_targets` | `bool` | `False` | When `True`, alerts whose target cannot be fetched are omitted from the result. When `False` (default), they are returned with `target=None` and a failure `status`. Marketplace alerts are always skipped regardless. | +| `skip_missing_targets` | `bool` | `False` | When `True`, alerts whose target cannot be fetched are omitted from the result. When `False` (default), they are returned with `target=None` and a failure `status`. Marketplace hits (no SDK route yet) are treated like any other unresolvable target. | ### Returns diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..5ef7b21 --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,5 @@ +{ + "venvPath": ".", + "venv": ".venv", + "exclude": ["**/node_modules", "**/__pycache__", "**/.*"] +} diff --git a/tests/test_helpers.py b/tests/test_helpers.py index 98735f3..7709377 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -257,12 +257,25 @@ def test_empty_alerts_returns_empty_list(self, call_url_mock, _watchers_mock): assert result == [] call_url_mock.assert_not_called() - def test_marketplace_url_is_skipped(self, call_url_mock, _watchers_mock): + def test_marketplace_url_returns_bare_alert(self, call_url_mock, watchers_mock): + # Marketplace hits have no SDK route, so they resolve as UnresolvableURL + # and come back as bare alerts (target=None) rather than being dropped. + call_url_mock.side_effect = UnresolvableURL("no route") + _no_watchers(watchers_mock) alert = _mock_alert(url=_MARKETPLACE_URL) with verity471.ApiClient(configuration) as api_client: result = fetch_alert_targets(_alerts_response(alert), api_client) + assert len(result) == 1 + assert result[0].alert is alert + assert result[0].target is None + assert result[0].status == AlertTargetStatus.UNRESOLVABLE + + def test_marketplace_url_omitted_when_skipping(self, call_url_mock, _watchers_mock): + call_url_mock.side_effect = UnresolvableURL("no route") + alert = _mock_alert(url=_MARKETPLACE_URL) + with verity471.ApiClient(configuration) as api_client: + result = fetch_alert_targets(_alerts_response(alert), api_client, skip_missing_targets=True) assert result == [] - call_url_mock.assert_not_called() def test_missing_link_is_skipped(self, _call_url_mock, _watchers_mock): alert = _mock_alert() diff --git a/verity471/helpers/alerts.py b/verity471/helpers/alerts.py index c6408fd..fda3913 100644 --- a/verity471/helpers/alerts.py +++ b/verity471/helpers/alerts.py @@ -327,8 +327,10 @@ def fetch_alert_targets( default (``False``) the alert is still returned with ``target=None`` and a non-``OK`` :class:`AlertTargetStatus` (plus a ``status_reason``) so callers can see it failed and why; when ``True`` such alerts are omitted from the - result entirely. Marketplace alerts are always skipped silently, regardless - of either flag. + result entirely. Marketplace alerts have no SDK route yet, so they are + treated like any other unresolvable target: returned as bare alerts with + ``status=UNRESOLVABLE`` by default, or omitted when *skip_missing_targets* + is ``True``. Args: alerts_response: The page returned by :meth:`AlertsApi.get_alerts_stream`. @@ -354,8 +356,6 @@ def fetch_alert_targets( """ def _fetch(alert: StreamingWatcherAlert) -> AlertTarget | None: url = alert.links.verity_api.href if (alert.links and alert.links.verity_api) else None - if url and "/integrations/marketplaces/" in url: - return None if not url: if raise_on_error: raise ValueError("Alert %s has no verity_api link" % alert.source_id)