Skip to content

feat(metras): add Metras internal-enrichment connector for fleet-presence lookups (#7042) - #7040

Open
Khidr6G wants to merge 8 commits into
OpenCTI-Platform:masterfrom
Khidr6G:feature/metras-internal-enrichment
Open

feat(metras): add Metras internal-enrichment connector for fleet-presence lookups (#7042)#7040
Khidr6G wants to merge 8 commits into
OpenCTI-Platform:masterfrom
Khidr6G:feature/metras-internal-enrichment

Conversation

@Khidr6G

@Khidr6G Khidr6G commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Proposed changes

  • Add a new INTERNAL_ENRICHMENT connector for the Metras EDR platform
    (api.metras.sa, X-API-KEY) under internal-enrichment/metras/.
  • Answers "have I seen this in my fleet?" for IPv4-Addr and StixFile observables:
    • IPv4-Addr → Metras EDR alerts (agent_ip) + endpoint inventory (interface_ip).
    • StixFile → Metras binary list (sha256/sha1) + binary details (md5).
    • Output: a context Note summarizing local presence, plus an optional
      Identity(identity_class="system") for each matched fleet endpoint and a related-to
      relationship. No Sighting is emitted (stix2 forbids sighting an SCO) and no
      Infrastructure objects are created.
  • Enrichment-safe behavior: custom TLP gate (no helper.check_max_tlp), refang before external
    calls, entity_in_scope guard with file → stixfile alias, and a raised ValueError on
    total lookup failure (never silently completes with 0 objects). Playbook-compatible
    (playbook_supported: true).
  • STIX id of the enriched entity resolved from enrichment_entity.standard_id then
    stix_entity.id (never the internal DB id); deterministic IDs for notes/identities/relationships.
  • Secrets typed pydantic.SecretStr; typed SDK config (TLPLevel, ListFromString);
    structured logging; CIS-hardened compose; non-root python:3.12-alpine image.
  • Unit tests for settings, API client, converter, and orchestration; pyproject.toml coverage
    config. black / isort --profile black / flake8 --ignore=E,W clean.
  • Validated end-to-end against OpenCTI 7.260529.0 (pycti==7.260529.0,
    connectors-sdk @7.260529.0, support_version ">=7.260529.0").

Related issues

Checklist

  • I consider the submitted work as finished
  • I have signed my commits using GPG key.
  • I tested the code for its functionality using different use cases
  • I added/update the relevant documentation (either on github or on notion)
  • Where necessary I refactored code to improve the overall quality

Further comments

Scope is intentionally limited to IPv4-Addr and StixFile: Metras has no value-filterable
lookup for domains/URLs (the /v4/threats/detail endpoint requires incident identifiers, not a
single observable value), so enriching those types is not possible with the current API.

Copilot AI review requested due to automatic review settings July 17, 2026 18:56
@Filigran-Automation Filigran-Automation added the community Contribution from the community. label Jul 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Metras INTERNAL_ENRICHMENT connector under internal-enrichment/metras/ to enrich IPv4-Addr and StixFile observables with “fleet presence” context from the Metras EDR API, emitting Notes and optional System identities + related-to relationships.

Changes:

  • Introduces the connector runtime (settings model, Metras API client with retries, enrichment orchestration, and STIX conversion).
  • Adds containerization + deployment artifacts (Dockerfile, compose, entrypoint, sample config, metadata/manifest, versioning).
  • Adds a unit test suite for settings, API client, orchestration, and utils (but no converter-specific tests despite the PR description stating otherwise).

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
internal-enrichment/metras/VERSION Declares connector version.
internal-enrichment/metras/src/requirements.txt Pins runtime dependencies (pycti, stix2, requests, connectors-sdk).
internal-enrichment/metras/src/main.py Connector entrypoint wiring settings → helper → connector run loop.
internal-enrichment/metras/src/connector/init.py Exposes main connector classes for imports.
internal-enrichment/metras/src/connector/settings.py Pydantic/SDK-based configuration models (connector + Metras settings).
internal-enrichment/metras/src/connector/utils.py Refang + basic validators used by connector/tests.
internal-enrichment/metras/src/connector/converter_to_stix.py Builds deterministic STIX Note/Identity/Relationship outputs.
internal-enrichment/metras/src/connector/connector.py Enrichment orchestration (scope/TLP gate, lookups, bundle send).
internal-enrichment/metras/src/metras_client/init.py Exports client + error type.
internal-enrichment/metras/src/metras_client/api_client.py HTTP client wrapper for Metras API endpoints + retry strategy.
internal-enrichment/metras/tests/test-requirements.txt Test dependency entrypoint for isolated test runs.
internal-enrichment/metras/tests/conftest.py Adds src/ to import path for tests.
internal-enrichment/metras/tests/test_main.py Unit tests for utils (refang/validators).
internal-enrichment/metras/tests/test_connector/test_settings.py Unit tests for settings/config model behavior.
internal-enrichment/metras/tests/test_connector/test_client.py Unit tests for HTTP client behaviors (mocked session).
internal-enrichment/metras/tests/test_connector/test_orchestration.py Unit tests for enrichment orchestration (mocked helper/client).
internal-enrichment/metras/README.md Connector documentation (scope, behavior, configuration, usage).
internal-enrichment/metras/pyproject.toml Coverage configuration for connector packages.
internal-enrichment/metras/entrypoint.sh Container entrypoint script.
internal-enrichment/metras/Dockerfile Container build (Alpine Python 3.12, non-root user).
internal-enrichment/metras/docker-compose.yml Hardened compose example for running the connector.
internal-enrichment/metras/config.yml.sample Sample YAML config for local/manual runs.
internal-enrichment/metras/.dockerignore Docker build context exclusions.
internal-enrichment/metras/metadata/connector_manifest.json Connector manifest metadata for OpenCTI ecosystem.

Comment thread internal-enrichment/metras/src/connector/utils.py Outdated
Comment thread internal-enrichment/metras/src/connector/connector.py
Comment thread internal-enrichment/metras/src/connector/connector.py
@Khidr6G Khidr6G changed the title feat(metras): add Metras internal-enrichment connector for fleet-presence lookups (#7038) feat(metras): add Metras internal-enrichment connector for fleet-presence lookups (#7042) Jul 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 26 out of 26 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (3)

internal-enrichment/metras/src/connector/connector.py:101

  • Logging context should be passed via the meta= keyword for consistency with other connectors, rather than as a positional dict argument. See e.g. external-import/email-intel-imap/src/base_connector/connector.py:103-123.
            self.helper.connector_logger.error(
                f"[CONNECTOR] {getattr(func, '__name__', 'call')} failed",
                {"error": str(exc)},
            )

internal-enrichment/metras/src/connector/connector.py:133

  • Logging context should be passed via the meta= keyword for consistency with other connectors, rather than as a positional dict argument. See e.g. external-import/email-intel-imap/src/base_connector/connector.py:103-123.
                self.helper.connector_logger.warning(
                    "[CONNECTOR] Skipped: TLP exceeds max",
                    {"tlp": level, "max": self._max_tlp.value},
                )

internal-enrichment/metras/src/connector/connector.py:166

  • Logging context should be passed via the meta= keyword for consistency with other connectors, rather than as a positional dict argument. See e.g. external-import/email-intel-imap/src/base_connector/connector.py:103-123.
            self.helper.connector_logger.error("[CONNECTOR] Error", {"error": str(err)})

Comment thread internal-enrichment/metras/src/metras_client/api_client.py
Comment thread internal-enrichment/metras/src/connector/connector.py
Comment thread internal-enrichment/metras/src/connector/connector.py
Comment thread internal-enrichment/metras/README.md Outdated
Comment thread internal-enrichment/metras/__metadata__/connector_manifest.json Outdated

@Powlinett Powlinett left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Khidr6G , thanks for your contribution.

Before addressing Copilot's comments, please rebase your branch onto the latest version of master to ensure the CI performs the same checks as on master 🙏

Also, please rename the connector folder so it has a unique name (currently same as external-import/metras).
The rule is: folder name == manifest's slug == docker's image name 👌

@Powlinett Powlinett left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Khidr6G , please find the requested changes in order to merge your PR.

Ping me if you need some assistance, thanks 🙏

Comment thread internal-enrichment/metras/__metadata__/connector_config_schema.json Outdated
Comment thread internal-enrichment/metras/__metadata__/connector_manifest.json Outdated
Comment thread internal-enrichment/metras/__metadata__/connector_manifest.json Outdated
Comment thread internal-enrichment/metras/VERSION Outdated
Comment thread internal-enrichment/metras/docker-compose.yml Outdated
Comment thread internal-enrichment/metras/config.yml.sample Outdated
Comment thread internal-enrichment/metras/src/requirements.txt Outdated
Comment thread internal-enrichment/metras/src/requirements.txt Outdated
Comment thread internal-enrichment/metras/src/connector/settings.py Outdated
Comment thread internal-enrichment/metras/src/connector/converter_to_stix.py Outdated
Comment thread internal-enrichment/metras-enrichment/src/connector/connector.py Outdated
@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.58559% with 48 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
.../metras-enrichment/src/metras_client/api_client.py 78.81% 25 Missing ⚠️
...hment/metras-enrichment/src/connector/connector.py 86.45% 21 Missing ⚠️
...nrichment/metras-enrichment/src/connector/utils.py 89.47% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master    #7040       +/-   ##
===========================================
+ Coverage   35.64%   84.63%   +48.98%     
===========================================
  Files        2048       10     -2038     
  Lines      125310      716   -124594     
===========================================
- Hits        44672      606    -44066     
+ Misses      80638      110    -80528     
Files with missing lines Coverage Δ
...chment/metras-enrichment/src/connector/__init__.py 100.00% <100.00%> (ø)
...tras-enrichment/src/connector/converter_to_stix.py 100.00% <100.00%> (ø)
...chment/metras-enrichment/src/connector/settings.py 100.00% <100.00%> (ø)
...nt/metras-enrichment/src/metras_client/__init__.py 100.00% <100.00%> (ø)
...nrichment/metras-enrichment/src/connector/utils.py 89.47% <89.47%> (ø)
...hment/metras-enrichment/src/connector/connector.py 86.45% <86.45%> (ø)
.../metras-enrichment/src/metras_client/api_client.py 78.81% <78.81%> (ø)

... and 2046 files with indirect coverage changes

📢 Thoughts on this report? Let us know!

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Contribution from the community.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(metras): Add Metras EDR connector suite (external-import, internal-enrichment, stream)

5 participants