feat(ctm360-threatcover): add CTM360 ThreatCover TAXII 2.1 connector (#6733)#6734
feat(ctm360-threatcover): add CTM360 ThreatCover TAXII 2.1 connector (#6733)#6734SamuelHassine wants to merge 4 commits into
Conversation
…2.1 (#6733) Add a dedicated external-import connector for the CTM360 ThreatCover module. It polls the ThreatCover TAXII 2.1 "Observables" collection (incrementally via the added_after filter and connector state, following more/next pagination), imports the returned STIX 2.1 objects, attributes SDOs to a CTM360 ThreatCover author identity and applies a configurable TLP marking. Built with the standard taxii2-client TokenAuth, modeled on the existing CTM360 connector family. Includes client + converter + connector unit tests, generated config schema/doc, README, manifest, config sample and docker-compose.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #6734 +/- ##
===========================================
- Coverage 31.03% 0.39% -30.65%
===========================================
Files 1986 1901 -85
Lines 122166 119772 -2394
===========================================
- Hits 37919 474 -37445
- Misses 84247 119298 +35051
📢 Thoughts on this report? Let us know! 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds a new external-import connector (ctm360-threatcover) to ingest CTM360 ThreatCover observables/indicators from a TAXII 2.1 collection into OpenCTI with incremental polling via added_after and TAXII pagination.
Changes:
- Introduces a TAXII 2.1 client, STIX post-processing (author + TLP marking), and connector orchestration/state handling.
- Adds connector configuration models plus generated metadata artifacts (manifest, JSON schema, config doc) and deployment assets (Dockerfile, compose, samples, README).
- Adds unit tests for the TAXII client, converter, settings validation, and connector runtime behavior.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| external-import/ctm360-threatcover/src/ctm360_threatcover_client/api_client.py | TAXII 2.1 client with pagination and error wrapping. |
| external-import/ctm360-threatcover/src/ctm360_threatcover_client/init.py | Exposes client + exception at package level. |
| external-import/ctm360-threatcover/src/connector/converter_to_stix.py | Applies TLP marking and author attribution to pulled STIX objects. |
| external-import/ctm360-threatcover/src/connector/connector.py | Main connector run loop: state handling, bundling, and OpenCTI work item usage. |
| external-import/ctm360-threatcover/src/connector/settings.py | Pydantic settings for OpenCTI + connector + CTM360 ThreatCover namespace. |
| external-import/ctm360-threatcover/src/connector/init.py | Exposes settings + connector class. |
| external-import/ctm360-threatcover/src/main.py | Connector entrypoint wiring settings → helper → connector. |
| external-import/ctm360-threatcover/src/requirements.txt | Connector runtime dependencies. |
| external-import/ctm360-threatcover/tests/tests_ctm360_threatcover_client/test_api_client.py | Unit tests for TAXII client pagination/filters/error behavior. |
| external-import/ctm360-threatcover/tests/tests_connector/test_converter.py | Unit tests for converter attribution/marking/passthrough behavior. |
| external-import/ctm360-threatcover/tests/tests_connector/test_connector.py | Unit tests for connector orchestration/state updates and error handling. |
| external-import/ctm360-threatcover/tests/tests_connector/test_settings.py | Unit tests for settings validation (valid/invalid configs). |
| external-import/ctm360-threatcover/tests/test_main.py | Smoke tests for settings/helper/connector instantiation. |
| external-import/ctm360-threatcover/tests/conftest.py | Pytest fixtures to mock heavy pycti helper dependencies. |
| external-import/ctm360-threatcover/tests/test-requirements.txt | Test dependency pinning. |
| external-import/ctm360-threatcover/README.md | Connector documentation (installation/config/deployment/behavior). |
| external-import/ctm360-threatcover/Dockerfile | Container build for the connector. |
| external-import/ctm360-threatcover/entrypoint.sh | Container entrypoint. |
| external-import/ctm360-threatcover/docker-compose.yml | Docker Compose deployment example. |
| external-import/ctm360-threatcover/config.yml.sample | Sample config for manual deployment. |
| external-import/ctm360-threatcover/metadata/connector_manifest.json | Connector manifest metadata (catalog/registry). |
| external-import/ctm360-threatcover/metadata/connector_config_schema.json | Generated env-var JSON schema for config validation/docs. |
| external-import/ctm360-threatcover/metadata/CONNECTOR_CONFIG_DOC.md | Generated human-readable config documentation. |
…axii2 connector (#6733) Match the model of the existing external-import/taxii2 connector: - Use TAXII server discovery (taxii2client v20/v21 Server from a discovery_url) and resolve the configured collection by id or title, instead of building a raw collection URL. - Support the same authentication options: token (default), custom API-key header, and HTTP basic, plus optional client certificate and a v21 toggle. - Keep the same more/next pagination and added_after incremental polling. The modern connectors-sdk scaffold is kept (consistent with the rest of the CTM360 connector family). Updates settings, client, connector wiring, tests, generated config schema/doc, README, config sample and docker-compose.
Address the Copilot review threads plus an independent senior review. - api_client.py: when a TAXII page reports more=true without a next cursor, raise Ctm360ThreatcoverAPIError instead of silently returning a partial page. Returning there would let the connector advance added_after and permanently skip the remaining objects. - connector.py: initialize work_id before the try block and finalize the work item as in_error in the except handlers, so a failure no longer leaves a "running" work entry; state is intentionally not advanced on error so the next run retries. - converter_to_stix.py: map tlp_level "clear" to the OpenCTI TLP:CLEAR custom statement marking (definition_type "statement" + x_opencti_definition) instead of the legacy stix2.TLP_WHITE, via a shared _statement_marking() helper that also builds TLP:AMBER+STRICT with allow_custom (matching connectors-sdk TLPMarking). - docker-compose.yml / config.yml.sample: mark CONNECTOR_SCOPE / scope as mandatory (it is required by the generated config schema). - README.md: fix the TOC anchor, align the OpenCTI minimum version with the manifest (6.8.12), and fix the Debugging logger example; fix the test-requirements grammar. - tests: cover the more-without-next abort, the failed-work finalization (and that state is not advanced on error), and the TLP:CLEAR / AMBER+STRICT marking shapes.
Review and fix pass completeIndependent senior review of the full connector plus all 11 automated review threads addressed, fixes pushed in 78ebaef. Data integrity (the important one)
TLP markings (
Samples / docs
Tests: added coverage for the more-without-next abort, the failed-work finalization (and that state is not advanced on error), and the TLP:CLEAR / AMBER+STRICT marking shapes. 36 tests pass; CI: all checks green. Blocker: self-approval is not possible (I am the PR author), so one maintainer approving review is still required before merge. |
…defaults - converter_to_stix.py: the inline comment said SCOs use the OpenCTI custom property, but SCOs are passed through unattributed (only SDOs get created_by_ref). Reworded to match the actual behavior. - README: CONNECTOR_NAME and CONNECTOR_LOG_LEVEL are optional with defaults (CTM360 ThreatCover / error), not mandatory, matching the generated schema; fixed the "you environment" -> "your environment" typo.
Review-and-fix pass summaryIndependent senior re-review of the full
Remaining (non-CI) blocker: |
Proposed changes
New external-import connector for the CTM360 ThreatCover module.
ThreatCover exposes its curated indicators/observables through a TAXII 2.1 collection, so the connector:
added_afterfilter and connector state, following TAXII pagination (more/next);added_after.It is built with the standard
taxii2-clientlibrary and modeled on the generic OpenCTItaxii2connector, supporting the same authentication options (token by default, custom API-key header, or HTTP basic, plus optional client certificate and a TAXII 2.0/2.1 toggle). It is consistent with the existing CTM360 connector family (CyberBlindSpot / Cyna / HackerView), which cover the REST-based modules; ThreatCover is a distinct, TAXII-native feed.Related issues
Closes #6733
Types of changes
Checklist
black,isort) and linting (flake8, STIX id pylint) pass__metadata__config schema and documentationREADME.md,config.yml.sample,docker-compose.ymlandconnector_manifest.jsonFurther comments
OpenCTI's generic TAXII2 connector can also consume this feed; this dedicated connector provides a preset, branded ThreatCover integration with sensible defaults. The TAXII discovery URL and collection id are tenant-specific and therefore configurable. Note that the
/api/v2/incidentsREST endpoint belongs to the separate CyberBlindspot module, not ThreatCover.Maintainer review (independent review-and-fix)
Independent senior review of the full connector across several passes, on top of the automated review threads. Substantive fixes:
more=truewithout anextcursor, the client raisesCtm360ThreatcoverAPIErrorinstead of returning a partial page; combined with finalizing the work item in error and not advancingadded_afteron failure, a run retries rather than permanently skipping data.work_idis initialized before thetryand the OpenCTI work item is closedin_erroron failure (no dangling "running" entries).clearmaps to the OpenCTI TLP:CLEAR custom statement marking (and TLP:AMBER+STRICT is built withallow_customand directx_opencti_*kwargs) via a shared_statement_marking()helper, matching connectors-sdk'sTLPMarkinginstead of the legacystix2.TLP_WHITE.CONNECTOR_SCOPE/scopemarked mandatory (required by the generated schema);CONNECTOR_NAME/CONNECTOR_LOG_LEVELcorrected to optional with their real defaults (CTM360 ThreatCover/error); README TOC anchor, minimum version (6.8.12), Debugging example and a "your environment" typo fixed.Status
All CI checks are green (tests, lint/format, STIX ID linter,
codecov/patchandcodecov/project) and there are 0 unresolved review threads.mergeStateStatusis BLOCKED only becausereviewDecisionisREVIEW_REQUIRED- the PR needs one approving review from a maintainer other than me (as the author I cannot self-approve).