feat(corelight-investigator): create external-import connector for alerts and detections (#6736)#6737
feat(corelight-investigator): create external-import connector for alerts and detections (#6736)#6737SamuelHassine wants to merge 4 commits into
Conversation
…erts and detections (#6736) Add an external-import connector for Corelight Investigator (SaaS NDR). It periodically queries the Investigator Detections and Alerts API (bearer API key), maps each alert/detection to a STIX Incident with the normalized severity (1-10) mapped to the OpenCTI severity, extracts the source/destination IP observables and relates them to the Incident, and attributes everything to a Corelight Investigator author identity with a configurable TLP. Imports are incremental via connector state. The query endpoint path is configurable (the in-product API reference documents the exact paths). Includes client + converter + connector unit tests, generated config schema/doc, README, manifest, config sample and docker-compose.
There was a problem hiding this comment.
Pull request overview
Adds a new external-import connector under external-import/corelight-investigator/ to pull Corelight Investigator “Detections and Alerts” incrementally, convert them into STIX 2.1 Incidents plus related IP observables, and send bundles to OpenCTI with stateful scheduling and configurable TLP.
Changes:
- Implemented a Corelight Investigator HTTP client with basic retry/backoff and response-envelope normalization.
- Implemented STIX conversion + connector runtime (stateful incremental
since, bundling, scheduling). - Added full connector packaging (Docker, compose, sample config, metadata) and unit tests for client/settings/converter/connector.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| external-import/corelight-investigator/src/corelight_investigator_client/api_client.py | Requests-based API client with retries/backoff and payload extraction. |
| external-import/corelight-investigator/src/corelight_investigator_client/init.py | Exposes client + error types as a small import surface. |
| external-import/corelight-investigator/src/connector/converter_to_stix.py | Alert/detection → STIX Incident + IP observables + relationships conversion. |
| external-import/corelight-investigator/src/connector/connector.py | Connector orchestration: stateful “since”, bundling, send, work handling, scheduling. |
| external-import/corelight-investigator/src/connector/settings.py | Pydantic/connectors-sdk settings models for OpenCTI + connector + Corelight config. |
| external-import/corelight-investigator/src/connector/init.py | Exposes connector entry classes. |
| external-import/corelight-investigator/src/main.py | Runtime entrypoint wiring settings → helper → connector. |
| external-import/corelight-investigator/src/requirements.txt | Connector runtime dependencies. |
| external-import/corelight-investigator/tests/conftest.py | Pytest fixtures/mocking for OpenCTIConnectorHelper. |
| external-import/corelight-investigator/tests/test_main.py | Smoke tests for settings/helper/connector instantiation. |
| external-import/corelight-investigator/tests/test-requirements.txt | Test dependency pinning for this connector. |
| external-import/corelight-investigator/tests/tests_corelight_investigator_client/test_api_client.py | Unit tests for API client behavior (envelope parsing, params, errors, rate-limit retry). |
| external-import/corelight-investigator/tests/tests_connector/test_settings.py | Unit tests for settings validation behavior. |
| external-import/corelight-investigator/tests/tests_connector/test_converter.py | Unit tests for severity mapping, incident creation, observable creation. |
| external-import/corelight-investigator/tests/tests_connector/test_connector.py | Unit tests for connector orchestration, bundling, and state updates. |
| external-import/corelight-investigator/Dockerfile | Container build for the connector. |
| external-import/corelight-investigator/entrypoint.sh | Container entrypoint wrapper. |
| external-import/corelight-investigator/docker-compose.yml | Example deployment configuration. |
| external-import/corelight-investigator/config.yml.sample | Manual deployment sample configuration. |
| external-import/corelight-investigator/README.md | Connector documentation and configuration reference. |
| external-import/corelight-investigator/metadata/connector_manifest.json | Connector marketplace/manifest metadata. |
| external-import/corelight-investigator/metadata/connector_config_schema.json | Generated config schema for the connector’s env vars. |
| external-import/corelight-investigator/metadata/CONNECTOR_CONFIG_DOC.md | Generated connector configuration documentation. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #6737 +/- ##
===========================================
- Coverage 31.03% 0.42% -30.62%
===========================================
Files 1986 1901 -85
Lines 122166 119810 -2356
===========================================
- Hits 37919 508 -37411
- Misses 84247 119302 +35055
📢 Thoughts on this report? Let us know! 🚀 New features to boost your workflow:
|
…ident ids Address the Copilot review on the new connector plus an independent senior review. - converter: TLP:CLEAR is no longer aliased to stix2.TLP_WHITE. CLEAR and AMBER+STRICT are now built as custom statement markings through a shared _statement_marking helper (matching connectors-sdk TLPMarking.to_stix2_object), so OpenCTI shows the correct TLP label instead of TLP:WHITE / TLP:AMBER. - converter: Incident.generate_id is seeded with the source timestamp only. When an alert has no usable timestamp the STIX created/modified still fall back to "now", but the id seed is None, so a re-imported alert keeps a stable Incident id instead of creating a duplicate on every run. - connector: finalize the initiated work with in_error=True on the API-error and generic-exception paths, so a failed run no longer leaves a dangling in-progress work in OpenCTI. - client/deps: type _request params as Optional[dict]; drop a stray space in the pydantic version pin. - tests: cover the distinct TLP:CLEAR marking, the deterministic incident id, the source-timestamp passthrough, _parse_timestamp, and the in-error work finalize.
Review-and-fix pass summaryIndependent senior re-review of the full new connector plus the two open Copilot threads. Code fixes (commit 40c75e5):
Tests (commits 40c75e5, 9988e06): added coverage for the distinct TLP:CLEAR marking, the deterministic Incident id, the source-timestamp passthrough, Status: all CI checks are green (codecov/patch 88.44%, target 80%), Remaining (non-CI) blocker: |
…doc fixes - converter_to_stix.py: seed Incident.generate_id with the alert id in the name (not just the display name), so distinct alerts that share a name no longer collapse into one Incident. When the alert has no usable timestamp, created/modified now fall back to a fixed sentinel instead of "now", so a re-imported alert keeps a stable id and is not re-sent with drifting created/modified each run. - docs: mark scope / CONNECTOR_SCOPE mandatory in config.yml.sample and docker-compose.yml (required by the generated schema), and align the README minimum version to OpenCTI >= 6.8.12 (matching the manifest support_version). Covered by new converter tests for the distinct-id and stable-timestamp behavior.
Review-and-fix pass summaryIndependent senior re-review of the full
Remaining (non-CI) blocker: |
| Table of Contents | ||
|
|
||
| - [OpenCTI Corelight Investigator Connector](#opencti-external-ingestion-connector-corelight-investigator) | ||
| - [Introduction](#introduction) | ||
| - [Installation](#installation) |
| The connector can be debugged by setting the appropriate log level. | ||
| Note that logging messages can be added using `self.helper.connector_logger,{LOG_LEVEL}("Sample message")`, i. | ||
| e., `self.helper.connector_logger.error("An error message")`. |
Proposed changes
New external-import connector for Corelight Investigator (SaaS NDR).
On a schedule the connector:
EventTyperecorded as the incident type;related-torelationships from the Incident to those observables;Related issues
Closes #6736
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
The exact REST path/parameters of the Investigator Detections and Alerts API are documented in the in-product API reference (require a tenant account), so the query endpoint path is configurable via
alerts_pathwith a documented default, and the response parser accepts the common envelope keys (data/alerts/detections/results). This is the import side of a Corelight integration; the Corelight open sensor consumes intel via Zeek/TAXII (e.g. OpenCTI's native TAXII2 live feed) rather than an outbound IOC API.Maintainer review (independent review-and-fix)
Independent senior review of the full connector, on top of the automated review threads. Substantive fixes:
converter_to_stix.py: TLP:CLEAR and TLP:AMBER+STRICT are built as custom statement MarkingDefinitions via a shared_statement_markinghelper (matching connectors-sdkTLPMarking.to_stix2_object), so OpenCTI shows the correct TLP label instead of aliasingstix2.TLP_WHITE/TLP_AMBER.converter_to_stix.py(deterministic ids):Incident.generate_idis seeded with the alert id in the name (so distinct alerts that share a name do not collapse into one Incident) plus the source timestamp; when an alert has no usable timestamp,created/modifiedfall back to a fixed sentinel instead of "now", so a re-imported alert keeps a stable id and is not re-sent with drifting timestamps each run.connector.py:work_idis initialized before thetryand the initiated work is finalized within_error=Trueon both error paths; a fetch failure raises (the client raises after retries), solast_runis not advanced on error and the next run retries.scope/CONNECTOR_SCOPEmarked mandatory inconfig.yml.sampleanddocker-compose.yml(required by the generated schema); the README minimum version is aligned to OpenCTI >= 6.8.12 (matching the manifestsupport_version).Tests
Unit tests cover the settings model, the API client (request shaping, retries, error wrapping), the converter (TLP:CLEAR / AMBER+STRICT marking shapes, severity mapping,
_parse_timestamp, deterministic and collision-free incident ids, stable fallback timestamps, IP observable extraction + relationships) and the connector (work finalizedin_erroron both error paths). 42 unit tests pass;black/isort/flake8clean locally.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).