Conversation
…ients Add platform-specific API methods to 4 connectors, all surfaced automatically via capabilities(). No existing code removed or modified. Feedly (32 new methods): - User profile: get/update - Subscriptions: list/subscribe/unsubscribe - Boards: list/get/create/delete/contents/save-article/remove-article - Streams: get_stream_contents, get_stream_ids (with continuation cursors) - Articles: get/batch-get/mark-as-read - Tags: list/tag-entries/untag/delete - AI entity search: search_entities/get_entity/get_entity_articles - Leo/Enterprise: get_ai_alerts, get_threat_landscape - OPML export CloudSEK (28 new methods): - Alerts: list (with all filters) + get + add_comment + 6 category helpers (credential_leaks, brand_abuse, phishing, dark_web, exposed_assets, code_leaks) - Indicators: search + domain/IP/email intelligence lookups - Threat actors: list/get/get_actor_alerts - Malware families: list/get - Watchlist: list/add/remove keywords - Dashboard: executive_summary, risk_score, export_alerts - Asset management: list/add/remove monitored assets DefenderTI (27 new methods): - TI Indicators (enhanced): list/get/create/update + bulk create/update/delete - Intelligence articles: list/get/get_indicators - Host intelligence: get + trackers/components/cookies/ssl_certs/resolutions/subdomains - SSL certificates: get/get_related_hosts - WHOIS: get_record, search_by_registrant - Vulnerability intelligence: get CVE + components/articles - Intelligence profiles (threat actors): list/get/get_indicators Anomali ThreatStream (32 new methods): - Intelligence: list (typed filters) + import_bulk + update_status + tag + export - Threat actors: list/get/indicators/create - Malware families: list/get/indicators - Campaigns: list/get/indicators - Vulnerabilities: list/get - Incidents: list/get/create/update + add_indicators - Trusted circles: list/get/list_indicators - Feeds: list/get/run - Rules: list/create - Reports: list/get https://claude.ai/code/session_01BDoue9HxB83ijLzFARAugq
Add platform-specific API methods to 5 connectors, all surfaced via capabilities(). No existing code removed or modified. Whistic (26 new methods): - Profiles: list/get templates - Vendor management: search/update/invite/risk-summary/documents/contacts - Assessment lifecycle: bulk_request/resend/archive/get_sections - Risk exceptions: list/create - Portfolio & reporting: network_stats/categories/integrations RiskRecon (24 new methods): - Company discovery: list (filtered)/search/get_by_domain/add/remove - Scoring & trends: score_history/portfolio_summary/industry_benchmarks - Findings: get_critical/list_remediated/get_detail/list_asset_findings - Criteria: list/get with remediation guidance - Assets: get/list_open_ports - Action plans: list/create/update - Contacts: list_company_contacts Nucleus (19 new methods): - Projects: list/get - Vulnerabilities: list (typed)/get/get_assets/accept_risk/reopen - Assets: list/get/list_asset_vulnerabilities - Statistics: get_statistics/get_sla_violations - Tags: list/create/assign_to_asset - Connectors: list/get_status/trigger_sync - SLA policies: list Rapid7 (26 new methods): - InsightVM vulns: list/get/solutions - InsightVM assets: list/get/vulnerabilities/services/search - InsightVM sites & scans: list_sites/get_site/list_scans/get_scan/create_scan/remediation_report - Threat Command IOCs: lookup/list/submit - Threat Command actors: list/get - Threat Command CVEs: list/get - Threat Command alerts: dark_web/brand/get/update_status - Threat Command search: search_intelligence ExtraHop (30 new methods): - Detections: get/update/search/add_note/list_notes - Devices: get/search/get_alerts/get_activity/list_peers - Custom device groups: list/create - Network locality: list/create - Records: search_records_typed - Metrics: query_metrics - Watchlists: list/create/add_devices - Administration: get_appliance_info/list_users/list_api_keys/get_audit_log - Threat intelligence: bulk_threat_lookup/get_collection/list_collections https://claude.ai/code/session_01BDoue9HxB83ijLzFARAugq
There was a problem hiding this comment.
Pull request overview
This pull request significantly expands several connector client classes by adding many new convenience methods for additional API endpoints (profiles/vendors/assessments, indicator management, vulnerability and asset queries, reporting, etc.) across multiple third-party integrations.
Changes:
- Added large sets of new API wrapper methods to multiple connector clients (Whistic, ThreatStream, RiskRecon, Rapid7, Nucleus, Feedly, ExtraHop, DefenderTI, CloudSEK).
- Introduced additional typed filtering/pagination helpers and bulk operations for common workflows (e.g., indicator import/tagging, vendor invitations, findings retrieval).
- Expanded “domain-specific” surface area for connectors well beyond the existing CRUD + STIX translation methods.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| gnat/connectors/whistic/client.py | Adds profile/vendor/assessment lifecycle helper methods. |
| gnat/connectors/threatstream/client.py | Adds typed intelligence operations plus additional entity APIs (actors, malware, campaigns, incidents, etc.). |
| gnat/connectors/riskrecon/client.py | Adds company discovery/search, scoring history, findings/criteria/assets/action-plan helpers. |
| gnat/connectors/rapid7/client.py | Adds InsightVM and Threat Command helper methods for vulnerabilities/assets/scans/IOCs/alerts. |
| gnat/connectors/nucleus/client.py | Adds project, vulnerability, asset, statistics, tags, connectors, and SLA policy helpers. |
| gnat/connectors/feedly/client.py | Adds user profile, subscriptions, boards, streams, articles, tags, entity search, enterprise alerts, OPML export helpers. |
| gnat/connectors/extrahop/client.py | Adds expanded detections/devices/records/metrics/watchlists/admin/threat-intel helper methods. |
| gnat/connectors/defenderti/client.py | Adds expanded TI indicator operations plus articles/hosts/SSL/WHOIS/vuln/intel profile helpers. |
| gnat/connectors/cloudsek/client.py | Adds alert, indicator, actor, watchlist, reporting, and asset management helper methods. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| self, | ||
| indicators: list[dict[str, Any]], | ||
| trusted_circles: list[int] | None = None, | ||
| tags: list[str] | None = None, |
There was a problem hiding this comment.
This file targets Python >=3.9 (pyproject.toml + Ruff target-version=py39), but it does not use from __future__ import annotations. Using PEP 604 union annotations here (e.g., list[int] | None, int | str) will raise at import time on Python 3.9 (TypeError when evaluating annotations), breaking the connector. Add from __future__ import annotations near the top of the file or replace these with Optional[...] / Union[...] (or stringified annotations).
| def list_vulnerabilities( | ||
| self, | ||
| severity: str = "", | ||
| cvss_min: float | None = None, | ||
| exploitable: bool | None = None, | ||
| page: int = 1, | ||
| page_size: int = 100, | ||
| ) -> list[dict[str, Any]]: |
There was a problem hiding this comment.
This module is expected to support Python 3.9 (project requires-python >=3.9), but it lacks from __future__ import annotations. The new X | None type annotations are evaluated at import time and will fail on Python 3.9. Add the future import at the top of the file (after the module docstring) or rewrite these annotations using Optional[...] / Union[...].
| status: str = "", | ||
| cve_id: str = "", | ||
| kev: bool = False, | ||
| epss_min: float | None = None, |
There was a problem hiding this comment.
This file does not import from __future__ import annotations, but the new signature uses PEP 604 union syntax (float | None). On Python 3.9 this will error at import time when annotations are evaluated. Add the future import at the top of the file or switch to Optional[float] (and similar) for 3.9 compatibility.
| epss_min: float | None = None, | |
| epss_min: Optional[float] = None, |
| payload: dict[str, Any] = { | ||
| "limit": limit, | ||
| "filter": { | ||
| "field": "participants", | ||
| "operator": "includes", | ||
| "operand": {"type": "device", "id": int(device_id)}, |
There was a problem hiding this comment.
device_id is typed as int | str, but this builds the filter using int(device_id). Passing a non-numeric string will raise ValueError before the request is sent. Either constrain the type to int, or avoid coercion / validate and raise a clearer GNATClientError when conversion fails.
| payload: dict[str, Any] = { | |
| "limit": limit, | |
| "filter": { | |
| "field": "participants", | |
| "operator": "includes", | |
| "operand": {"type": "device", "id": int(device_id)}, | |
| try: | |
| numeric_device_id = int(device_id) | |
| except (TypeError, ValueError) as exc: | |
| raise GNATClientError( | |
| f"Invalid device_id {device_id!r}: expected an integer or numeric string." | |
| ) from exc | |
| payload: dict[str, Any] = { | |
| "limit": limit, | |
| "filter": { | |
| "field": "participants", | |
| "operator": "includes", | |
| "operand": {"type": "device", "id": numeric_device_id}, |
| Parameters | ||
| ---------- | ||
| stream_id : str | ||
| URL-encoded Feedly stream ID. | ||
| ranked : str | ||
| Sort order: ``"newest"`` (default) or ``"oldest"``. | ||
| unread_only : bool | ||
| Filter to unread articles only. | ||
| """ | ||
| import urllib.parse as _up | ||
| encoded = _up.quote(stream_id, safe="") | ||
| params: dict[str, Any] = {"count": count, "ranked": ranked} |
There was a problem hiding this comment.
The docstring says stream_id is already URL-encoded, but the implementation URL-encodes it again (quote(stream_id, safe='')). This mismatch can lead to callers double-encoding IDs and getting 404s. Either update the docstring to state stream_id should be raw/unencoded, or remove the extra encoding and require callers to pass an encoded ID consistently.
| # ── Profiles (questionnaire templates) ─────────────────────────────────── | ||
|
|
||
| def list_profiles(self) -> list[dict[str, Any]]: | ||
| """List available Whistic security profile templates.""" | ||
| resp = self.get("/v1/profiles") |
There was a problem hiding this comment.
PR title suggests this change is about adding Claude documentation, but this PR also introduces large sets of new API wrapper methods across multiple connectors. If the intent is documentation-only, these code changes should be split into a separate PR (or the title/description should be updated to reflect the functional scope).
No description provided.