feat(metras): add Metras stream connector for blocklist sync (#7042)#7041
Open
Khidr6G wants to merge 3 commits into
Open
feat(metras): add Metras stream connector for blocklist sync (#7042)#7041Khidr6G wants to merge 3 commits into
Khidr6G wants to merge 3 commits into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #7041 +/- ##
===========================================
+ Coverage 35.64% 82.18% +46.54%
===========================================
Files 2048 9 -2039
Lines 125310 612 -124698
===========================================
- Hits 44672 503 -44169
+ Misses 80638 109 -80529
📢 Thoughts on this report? Let us know! 🚀 New features to boost your workflow:
|
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new OpenCTI STREAM connector under stream/metras/ that consumes a configured live stream and forwards supported file-path Indicators to the Metras EDR custom blocklist API, including create/update/delete handling and unit tests.
Changes:
- Introduces the Metras stream connector implementation (settings, stream listener/orchestration, indicator→blocklist conversion).
- Adds a shared Metras REST API client with retries and error handling for blocklist operations.
- Adds connector packaging/runtime assets (Dockerfile, compose, config sample, metadata manifest) and unit tests/coverage config.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| stream/metras/VERSION | Declares connector version. |
| stream/metras/tests/test-requirements.txt | Test dependency entrypoint for the connector’s requirements + pytest. |
| stream/metras/tests/test_main.py | Tests conversion logic (pattern→file paths, deterministic naming). |
| stream/metras/tests/test_connector/test_settings.py | Tests config defaults and SecretStr handling. |
| stream/metras/tests/test_connector/test_orchestration.py | Tests event processing behavior with mocked client/helper. |
| stream/metras/tests/test_connector/test_client.py | Tests API client request/response behavior with mocked HTTP. |
| stream/metras/tests/conftest.py | Ensures src/ is importable during tests. |
| stream/metras/src/requirements.txt | Pins runtime dependencies (pycti, pydantic, requests, connectors-sdk). |
| stream/metras/src/metras_client/api_client.py | Implements HTTP client for Metras API + blocklist endpoints. |
| stream/metras/src/metras_client/init.py | Exposes MetrasClient / MetrasAPIError package API. |
| stream/metras/src/main.py | Runtime entrypoint wiring settings → helper → connector. |
| stream/metras/src/connector/utils.py | Adds pure utility helpers (slugify). |
| stream/metras/src/connector/settings.py | Defines Pydantic settings models for connector + Metras config. |
| stream/metras/src/connector/converter_to_external.py | Converts OpenCTI Indicators to Metras blocklist payloads. |
| stream/metras/src/connector/connector.py | Stream listener + create/update/delete dispatch to Metras. |
| stream/metras/src/connector/init.py | Exports connector public symbols for imports. |
| stream/metras/README.md | Documents scope, configuration, and usage. |
| stream/metras/pyproject.toml | Coverage configuration for the connector modules. |
| stream/metras/entrypoint.sh | Container entrypoint script. |
| stream/metras/Dockerfile | Container build for the connector runtime. |
| stream/metras/docker-compose.yml | Example hardened compose service definition. |
| stream/metras/config.yml.sample | Sample YAML configuration for local runs. |
| stream/metras/.dockerignore | Docker build context pruning. |
| stream/metras/metadata/connector_manifest.json | Connector manifest metadata for the monorepo. |
| paths: list[str] = [] | ||
| if names and dirs: | ||
| for d in dirs: | ||
| sep = "" if d.endswith(("\\", "/")) else "\\" |
Contributor
Author
There was a problem hiding this comment.
fixed in the amended commit
Comment on lines
+49
to
+52
| self.helper.connector_logger.info("[CONNECTOR] Starting Metras stream listener") | ||
| # listen_stream() spawns a daemon thread and returns — keep the main | ||
| # thread alive so the process does not exit. | ||
| self.helper.listen_stream(message_callback=self._process_event) |
Contributor
Author
There was a problem hiding this comment.
fixed in the amended commit
| api_base_url: HttpUrl = Field( | ||
| default="https://api.metras.sa/api", | ||
| description="Base URL of the Metras API.", | ||
| examples=["https://api.metras.sa"], |
Contributor
Author
There was a problem hiding this comment.
fixed in the amended commit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed changes
STREAMconnector for the Metras EDR platform(
api.metras.sa,X-API-KEY) understream/metras/.Indicators whose pattern resolves to a filename / path to the Metras custom blocklist:
POST /v1/custom-blocklistPATCH /v1/custom-blocklist/{id}DELETE /v1/custom-blocklist/{id}opencti-<slug>) derived from theindicator name, not a volatile STIX id, so id changes on merge/re-import don't create
duplicates.
Metras exposes no create-IOC API for those;
/v1/custom-blocklistaccepts file paths only.msg.dataparsed as a JSON string (json.loads(...)["data"]),listen_stream()with a keep-alive main loop, per-event errors are caught and logged (theconnector never crashes the stream). Secrets typed
pydantic.SecretStr.python:3.12-alpineimage; CIS-hardened compose; requires a user-created, activatedOpenCTI live stream (
CONNECTOR_LIVE_STREAM_ID), documented in the README.pyproject.tomlcoverageconfig.
black/isort --profile black/flake8 --ignore=E,Wclean.7.260529.0(pycti==7.260529.0,connectors-sdk @7.260529.0,support_version ">=7.260529.0").Related issues
Checklist
Further comments
This is a uni-directional (OpenCTI → Metras) forwarder: it creates no OpenCTI bundles and does
not use the Work API. The file-path-only limitation is an API constraint, not a design choice —
Metras has no endpoint to create IP/domain/hash/YARA/Sigma IOCs.