Skip to content

feat(logrhythm-incidents): add external-import connector for LogRhythm cases (#6728)#6729

Open
SamuelHassine wants to merge 4 commits into
masterfrom
feature/logrhythm-incidents-external-import
Open

feat(logrhythm-incidents): add external-import connector for LogRhythm cases (#6728)#6729
SamuelHassine wants to merge 4 commits into
masterfrom
feature/logrhythm-incidents-external-import

Conversation

@SamuelHassine

@SamuelHassine SamuelHassine commented Jun 15, 2026

Copy link
Copy Markdown
Member

Proposed changes

This PR adds a new EXTERNAL_IMPORT connector external-import/logrhythm-incidents
that imports LogRhythm cases into OpenCTI as STIX Incidents. It is the import side
of a bidirectional LogRhythm integration (paired with the existing
stream/logrhythm connector that feeds LogRhythm lists from OpenCTI).

  • Authenticates with a LogRhythm API token (Bearer).
  • Periodically pulls cases from the LogRhythm Case API (/lr-case-api/cases),
    capped per run.
  • Converts each case to a STIX 2.1 Incident (name, summary, priority-based
    severity, timestamps, external reference to the case number), attributed to a
    LogRhythm author identity and marked with a configurable TLP.
  • Built on the modern connectors-sdk settings pattern, with unit tests and
    connector metadata (manifest, config schema, configuration documentation).

Related issues

Closes #6728

Checklist

  • My code follows the repository code style (isort, black, flake8, STIX-id pylint).
  • I have added unit tests covering the settings, the client, the converter and the connector.
  • I have updated the documentation (README, connector metadata).
  • Commits are signed.

Type of change

  • New feature (non-breaking change which adds functionality).

Maintainer review and fix pass

Independent senior review of the full connector plus the Copilot threads.

Correctness:

  • converter_to_stix.py: tlp_level='clear' now emits a distinct OpenCTI TLP:CLEAR statement marking (x_opencti_definition='TLP:CLEAR') via a shared _custom_tlp() helper (which also builds TLP:AMBER+STRICT) instead of aliasing stix2.TLP_WHITE.
  • converter_to_stix.py: _to_iso uses a deterministic epoch fallback (1970-01-01) for missing/invalid timestamps so Incident.generate_id / CaseIncident.generate_id stay stable - the previous datetime.now() fallback minted a new id (a duplicate object) on every run for records without a usable timestamp.
  • api_client.py: _request now fails fast on non-retriable 4xx (401/403/404) - only 429 and network/5xx errors are retried - and passes context via meta={...}.
  • connector.py: the work is marked to_processed in a finally so a failed run no longer leaves an "in progress" work item hanging; the docstring now reflects that cases become Case-Incidents and their alarms become Incidents.

Docs / consistency:

  • config.yml.sample, docker-compose.yml and README.md mark scope / CONNECTOR_SCOPE as required; the tlp_level option list now includes white; the compose placeholders use ChangeMe.
  • Tests: _load_config_dict overrides return -> Self (matching the SDK), the settings test asserts on str(err.value), a grammar typo is fixed, and tests were added for the TLP:CLEAR marking, the deterministic id, and the 4xx fail-fast path.

The apk update && apk upgrade Dockerfile line is kept on purpose - it is the shared pattern across the repo's stream/external-import connectors; slimming those images should be a consistent, repo-wide change rather than a one-off here.

Verified: 39/39 unit tests pass; black / isort / flake8 --select=F clean; all CI checks green (including codecov/patch and codecov/project); 0 unresolved review threads. Commits are GPG-signed.

Note: mergeStateStatus is BLOCKED only because the PR needs an approving review from a maintainer other than me (I am the author and cannot self-approve).

…m cases

Add a new EXTERNAL_IMPORT connector that periodically pulls LogRhythm cases via the Case API and imports them into OpenCTI as STIX Incidents. This is the import side of a bidirectional LogRhythm integration.

Refs #6728
Copilot AI review requested due to automatic review settings June 15, 2026 09:41
@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

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

Files with missing lines Patch % Lines
external-import/logrhythm-incidents/src/main.py 0.00% 13 Missing ⚠️
...hythm-incidents/src/logrhythm_client/api_client.py 87.32% 9 Missing ⚠️
...hythm-incidents/src/connector/converter_to_stix.py 95.12% 4 Missing ⚠️
...ort/logrhythm-incidents/src/connector/connector.py 96.07% 2 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (c691e18) and HEAD (0625aae). Click for more details.

HEAD has 114 uploads less than BASE
Flag BASE (c691e18) HEAD (0625aae)
connectors 118 4
Additional details and impacted files
@@             Coverage Diff             @@
##           master    #6729       +/-   ##
===========================================
- Coverage   32.26%    0.41%   -31.85%     
===========================================
  Files        1986     1901       -85     
  Lines      122165   119854     -2311     
===========================================
- Hits        39413      494    -38919     
- Misses      82752   119360    +36608     
Files with missing lines Coverage Δ
...port/logrhythm-incidents/src/connector/__init__.py 100.00% <100.00%> (ø)
...port/logrhythm-incidents/src/connector/settings.py 100.00% <100.00%> (ø)
...grhythm-incidents/src/logrhythm_client/__init__.py 100.00% <100.00%> (ø)
...ort/logrhythm-incidents/src/connector/connector.py 96.07% <96.07%> (ø)
...hythm-incidents/src/connector/converter_to_stix.py 95.12% <95.12%> (ø)
...hythm-incidents/src/logrhythm_client/api_client.py 87.32% <87.32%> (ø)
external-import/logrhythm-incidents/src/main.py 0.00% <0.00%> (ø)

... and 1120 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.

LogRhythm cases are case-management artifacts, so they must map to OpenCTI Case-Incidents (CustomObjectCaseIncident) rather than Incidents, which are reserved for alarms/detections. Add severity-based priority.

Refs #6728

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

…se-Incidents (#6728)

LogRhythm exposes two distinct concepts. Model them as two STIX entities:
alarms attached to a case become STIX Incidents, and the case itself becomes
a STIX Case-Incident that references those Incidents through object_refs.
Adds get_case_alarms to the client, create_incident plus risk-score mapping
to the converter, and a dual collection loop. Tests and docs updated.

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 24 out of 26 changed files in this pull request and generated 9 comments.

Comment thread external-import/logrhythm-incidents/src/connector/connector.py
Comment thread external-import/logrhythm-incidents/Dockerfile
Comment thread external-import/logrhythm-incidents/src/config.yml.sample
Comment thread external-import/logrhythm-incidents/README.md
Comment thread external-import/logrhythm-incidents/tests/test-requirements.txt Outdated
Comment thread external-import/logrhythm-incidents/src/config.yml.sample
…t and docs

Emit a distinct OpenCTI TLP:CLEAR marking for tlp_level='clear' instead of
aliasing stix2.TLP_WHITE, and build TLP:AMBER+STRICT the same way via a shared
helper. Use a deterministic epoch fallback for missing/invalid timestamps so
Incident.generate_id / CaseIncident.generate_id stay stable and re-runs do not
create duplicate objects.

_request now fails fast on non-retriable 4xx (401/403/404) - only 429 and
network/5xx errors are retried - and logs context via meta={...}. The connector
marks its work to_processed in a finally so a failed run does not leave an
"in progress" work item hanging, and its docstring now reflects Case-Incidents.

Docs: mark scope / CONNECTOR_SCOPE as required in config.yml.sample,
docker-compose.yml and README.md; add 'white' to the tlp_level option list;
normalise the compose placeholders to ChangeMe. Tests: align the
_load_config_dict overrides with the SDK (-> Self), assert on str(err.value),
fix a grammar typo, and add TLP:CLEAR / deterministic-id / 4xx-fail-fast tests.
@SamuelHassine

Copy link
Copy Markdown
Member Author

Review-and-fix pass summary

Independent senior review of the full new connector plus all the open Copilot threads, fixed in 0625aae.

Correctness (must-fix):

  • tlp_level='clear' now emits a distinct OpenCTI TLP:CLEAR statement marking (via a shared _custom_tlp() helper that also builds TLP:AMBER+STRICT) instead of aliasing stix2.TLP_WHITE.
  • _to_iso uses a deterministic epoch fallback (1970-01-01) for missing/invalid timestamps, so Incident.generate_id / CaseIncident.generate_id are stable - the previous datetime.now() fallback minted a new id (a duplicate object) on every run for records without a usable timestamp.

Robustness / consistency:

  • _request fails fast on non-retriable 4xx (401/403/404), retries only 429 and network/5xx, and logs via meta={...}.
  • The connector marks its work to_processed in a finally so a failed run no longer leaves a hanging "in progress" work item; the docstring now reflects Case-Incidents (with alarms as Incidents).
  • Docs: scope / CONNECTOR_SCOPE marked required in config.yml.sample / docker-compose.yml / README.md; white added to the tlp_level list; compose placeholders normalised to ChangeMe.
  • Tests: _load_config_dict overrides return -> Self, settings test asserts on str(err.value), grammar typo fixed, plus new tests for TLP:CLEAR, deterministic id, and 4xx fail-fast.
  • The Dockerfile apk update && apk upgrade line is kept on purpose (shared pattern across the repo's connectors); slimming those images is better done repo-wide.

Verified locally: 39/39 unit tests pass; black / isort / flake8 --select=F clean. CI: all checks green (tests, lint/format, STIX ID linter, codecov/patch and codecov/project); filigran/cla satisfied (organization member). Review threads: 0 unresolved. Title already matches the Conventional Commits convention; description updated to reflect the final state.

Remaining (non-CI) blocker: mergeStateStatus is BLOCKED only because reviewDecision is REVIEW_REQUIRED - the PR needs one approving review from a maintainer other than me. As the author I cannot self-approve, so this requires another Filigran maintainer.

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 24 out of 26 changed files in this pull request and generated no new comments.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(logrhythm-incidents): add external-import connector for LogRhythm cases

3 participants