Skip to content

feat(osint-industries): add manager-supported catalog config with max TLP gating (#7652) - #7704

Merged
Hugo Dupras (jabesq) merged 9 commits into
masterfrom
feat/7652-osint-industries-catalog
Sep 18, 2026
Merged

Hugo Dupras (jabesq) merged 9 commits into
masterfrom
feat/7652-osint-industries-catalog

Conversation

@jabesq

Copy link
Copy Markdown
Member

Proposed changes

  • Normalize the connector configuration files (.env.sample, config.yml.sample, docker-compose.yml, README.md) so every variable follows the OSINT_INDUSTRIES_* / osint_industries convention. This is the prerequisite for the config-schema generator to produce a correct catalog entry.
  • Replace pycti.get_config_variable + yaml.load with a Pydantic settings.py built on the connectors-sdk base classes (BaseConnectorSettings, BaseInternalEnrichmentConnectorConfig, BaseConfigModel). Configuration is now validated and typed at startup — a missing API key or a bogus TLP value fails immediately with a clear error instead of surfacing as an obscure runtime failure later. PyYAML is dropped from src/requirements.txt since nothing parses YAML by hand anymore.
  • Re-export ConnectorSettings from src/__init__.py. The config-schema generator resolves the settings class through from src import ConnectorSettings; without this re-export the catalog schema cannot be generated for this connector.
  • Give connector.id a repo-unique UUIDv4 default (cef186b0-…). Catalog-deployed connectors get a working identity out of the box, so operators no longer have to hand-craft a CONNECTOR_ID just to start the container.
  • Flip manager_supported: true in __metadata__/connector_manifest.json and commit the generated connector_config_schema.json + CONNECTOR_CONFIG_DOC.md. This is what actually makes the connector deployable and configurable from the OpenCTI connector catalog UI.
  • Add a OSINT_INDUSTRIES_MAX_TLP setting (default TLP:AMBER) enforced before any outbound call. OSINT Industries is a paid third-party source that processes personal data, so the gate deliberately runs at the very top of _process_message, before the client is touched: a selector marked above the maximum never leaves the platform. All TLP markings on the entity must pass, so the most restrictive one wins — an observable marked both TLP:GREEN and TLP:RED is treated as TLP:RED. Unmarked observables stay allowed, matching check_max_tlp's own None behaviour.
  • Make the connector playbook-compatible (playbook_compatible=True, bundle read from data["stix_objects"]). Every path that produces no enrichment — TLP refused, unsupported entity type, no usable value, API failure, empty result, nothing converted, unexpected error — now returns the incoming bundle untouched so the playbook pipeline continues instead of dead-ending at this step. Forwarding is gated on event_type being absent, so manual/automatic enrichment runs don't pointlessly re-send a bundle the platform already has, and the forward itself is best-effort so it can never mask the original outcome or break the listener loop.
  • Send bundles with cleanup_inconsistent_bundle=True, and append enriched objects to the original bundle rather than replacing it, so a playbook keeps the entities it was already carrying through the step.
  • Add unit tests for the settings, the TLP gate and the playbook paths (tests_connector/test_settings.py, test_main.py, expanded test_connector.py), covering each no-enrichment branch to lock in the "always give the bundle back" contract.

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

The max-TLP check is intentionally the first thing _process_message does rather than a filter on the results: since this is a paid source handling personal data, the requirement is that a too-sensitive selector is never transmitted at all, not merely that its results are discarded. For the same reason the check is conjunctive over all markings (most restrictive wins) instead of looking at a single "the" TLP.

On the playbook side, the guiding rule is that a step which cannot enrich must still be transparent: it hands the original bundle back rather than returning nothing, so inserting this connector into a playbook can never silently truncate the chain.

Scope note: this is a manager-supported pass, not a full "verified" one. The migration is deliberately structure-preserving — file layout, class names, the __main__.py entry point, logging and scheduling are all unchanged. Connector-linter checks VC304, VC312, VC319, VC320, VC321 and VC322 go from 1/6 to 6/6 against the pre-change baseline. Two known gaps remain out of scope here: VC308 (entry point is src/__main__.py, not src/main.py) and VC309 (relative imports). Both would require restructuring the package and are better handled in a dedicated follow-up.

…or playbooks (#7652)

Enrichment now stops before any call to the third-party API when the
observable carries a TLP above OSINT_INDUSTRIES_MAX_TLP.

The connector is also playbook-compatible: it declares
playbook_compatible=True, reads the former bundle from
data['stix_objects'], and hands it back untouched on every path that
produces no enrichment (TLP refused, unsupported entity, no usable
value, API failure, empty result, nothing converted, unexpected error)
so the playbook pipeline is not interrupted. Bundles are now sent with
cleanup_inconsistent_bundle=True.

Linter VC304, VC312, VC319, VC320, VC321 and VC322 go from 1/6 to 6/6.
Copilot AI lite review requested due to automatic review settings September 16, 2026 13:43
@jabesq Hugo Dupras (jabesq) added the filigran team Item from the Filigran team. label Sep 16, 2026
@github-actions

Copy link
Copy Markdown

🔴 Connector Linter errors detected

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

Migrates the OSINT Industries connector to SDK-based typed settings, catalog support, max-TLP enforcement, and playbook-compatible bundle handling.

Changes:

  • Adds Pydantic settings and generated catalog metadata.
  • Adds TLP gating and bundle forwarding behavior.
  • Expands tests and normalizes deployment documentation.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
internal-enrichment/osint-industries/tests/tests_connector/test_settings.py Updated as part of this pull request.
internal-enrichment/osint-industries/tests/test-requirements.txt Updated as part of this pull request.
internal-enrichment/osint-industries/tests/test_main.py Updated as part of this pull request.
internal-enrichment/osint-industries/tests/test_connector.py Updated as part of this pull request.
internal-enrichment/osint-industries/tests/conftest.py Updated as part of this pull request.
internal-enrichment/osint-industries/src/requirements.txt Updated as part of this pull request.
internal-enrichment/osint-industries/src/osint_industries/settings.py Updated as part of this pull request.
internal-enrichment/osint-industries/src/osint_industries/connector.py Updated as part of this pull request.
internal-enrichment/osint-industries/src/osint_industries/init.py Updated as part of this pull request.
internal-enrichment/osint-industries/src/init.py Updated as part of this pull request.
internal-enrichment/osint-industries/README.md Updated as part of this pull request.
internal-enrichment/osint-industries/docker-compose.yml Updated as part of this pull request.
internal-enrichment/osint-industries/config.yml.sample Updated as part of this pull request.
internal-enrichment/osint-industries/.env.sample Updated as part of this pull request.
internal-enrichment/osint-industries/metadata/connector_manifest.json Updated as part of this pull request.
internal-enrichment/osint-industries/metadata/connector_config_schema.json Updated as part of this pull request.
internal-enrichment/osint-industries/metadata/CONNECTOR_CONFIG_DOC.md Updated as part of this pull request.
Suppressed comments (1)

internal-enrichment/osint-industries/src/osint_industries/connector.py:117

  • The and original_stix_objects guard suppresses the forward whenever a playbook message contains an empty stix_objects list. That silently terminates the playbook on a valid no-enrichment input, contrary to the advertised always-forward contract; do not skip the forwarding call for an empty incoming bundle (or handle that case explicitly).
        if self._is_playbook_context(data) and original_stix_objects:

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

"""
original_stix_objects = self._former_bundle(data)
if self._is_playbook_context(data) and original_stix_objects:
self._send_bundle(original_stix_objects)
@jabesq
Hugo Dupras (jabesq) added this pull request to the merge queue Sep 18, 2026
Merged via the queue into master with commit f8b496b Sep 18, 2026
26 checks passed
@jabesq
Hugo Dupras (jabesq) deleted the feat/7652-osint-industries-catalog branch September 18, 2026 08:49
Helene Nguyen (helene-nguyen) pushed a commit to helene-nguyen/opencti-connectors that referenced this pull request Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

filigran team Item from the Filigran team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(osint-industries): migrate connector to the catalog

4 participants