Skip to content

feat(stairwell): add Stairwell internal-enrichment connector (#7095) - #7097

Open
zachdaniel-SW wants to merge 3 commits into
OpenCTI-Platform:masterfrom
zachdaniel-SW:feat/stairwell-internal-enrichment
Open

feat(stairwell): add Stairwell internal-enrichment connector (#7095)#7097
zachdaniel-SW wants to merge 3 commits into
OpenCTI-Platform:masterfrom
zachdaniel-SW:feat/stairwell-internal-enrichment

Conversation

@zachdaniel-SW

Copy link
Copy Markdown

Proposed changes

Adds internal-enrichment/stairwell, an INTERNAL_ENRICHMENT connector that
enriches StixFile, Domain-Name, IPv4-Addr, IPv6-Addr, and Autonomous-System
observables with Stairwell intelligence (MalEval verdict + monotonic score, AI
File Triage note, file metadata, YARA matches, variant discovery with
derived-from links, per-asset sightings, DNS history, IP intel, WHOIS).

Built to the current template: connectors-sdk + Pydantic settings, manifest,
entrypoint, thin main.py, playbook-compatible. STIX emitted via bundles with
deterministic IDs; no direct API writes. Detonation data intentionally excluded.

Related issues

Close #7095

Checklist

  • I consider the submitted work as finished
  • I tested the code for its functionality using different use cases
  • I have signed my commits using GPG key
  • I added/updated the relevant documentation
  • Where necessary I refactored code to improve overall quality

Further comments

Unit tests: 41 passing (pytest tests/). Config layer verified against real
pycti 7.260722.0 + connectors-sdk. Live end-to-end validation on OpenCTI 6.8.x
in progress — will confirm the "tested" box before requesting final review.

Copilot AI review requested due to automatic review settings July 23, 2026 23:56
@filigran-cla-bot

Copy link
Copy Markdown

Contributor License Agreement

Hey @zachdaniel-SW!

Thank you for your contribution to Filigran! Before we can merge this pull request, we need you to sign our Contributor License Agreement (CLA).

Why do we need a CLA?

The CLA helps protect both you and Filigran. It ensures that:

  • You have the right to make this contribution
  • Filigran can use and distribute your contribution
  • Your contribution remains open source

How to sign

You can sign the CLA using either of these methods:

  1. 🔗 Sign directlyClick here to review and sign the CLA
  2. 📧 Via email — Check your inbox (and spam folder) for a signing invitation from Concord

Once signed, this comment will be automatically updated.


CLA not signed yet

This is an automated message from the Filigran CLA Bot. If you have questions, please contact the maintainers.

@filigran-cla-bot filigran-cla-bot Bot added the cla:pending CLA signature required. label Jul 23, 2026
@Filigran-Automation Filigran-Automation added the community Contribution from the community. label Jul 23, 2026
@zachdaniel-SW

Copy link
Copy Markdown
Author

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 internal-enrichment/stairwell connector implementing Stairwell-based enrichment for OpenCTI observables (files, domains, IPs, ASNs), emitting results via STIX 2.1 bundles with notes/relationships/custom properties.

Changes:

  • Introduces a Stairwell API client + enrichment dispatchers for file/domain/ip/asn observables.
  • Adds STIX bundle/object construction utilities and scoring policy (monotonic OpenCTI score mapping).
  • Adds connector packaging (Dockerfile, compose, entrypoint, metadata) and a comprehensive unit test suite.

Reviewed changes

Copilot reviewed 27 out of 29 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal-enrichment/stairwell/src/tests/test-requirements.txt Test dependency list for Stairwell connector tests.
internal-enrichment/stairwell/src/tests/test_stix_builder.py Unit tests for STIX object/bundle builder helpers.
internal-enrichment/stairwell/src/tests/test_score_policy.py Unit tests for MalEval probability→score mapping and monotonic scoring.
internal-enrichment/stairwell/src/tests/test_network_enrichers.py Unit tests for domain/IP/ASN enrichment logic and emitted STIX shape.
internal-enrichment/stairwell/src/tests/test_file_enricher.py Unit tests for file enrichment behavior (notes, variants, sightings, exclusions).
internal-enrichment/stairwell/src/tests/conftest.py pytest path setup so connector.* imports resolve in tests.
internal-enrichment/stairwell/src/requirements.txt Runtime dependencies for the Stairwell connector.
internal-enrichment/stairwell/src/main.py Connector entrypoint wiring settings → helper → connector run loop.
internal-enrichment/stairwell/src/connector/stix_builder.py STIX 2.1 ID + object constructors and bundle serialization.
internal-enrichment/stairwell/src/connector/stairwell/score.py MalEval bucket scoring utilities.
internal-enrichment/stairwell/src/connector/stairwell/client.py Stairwell HTTP client (V1/V2 endpoints + retries + UI deep links).
internal-enrichment/stairwell/src/connector/stairwell/init.py Stairwell subpackage exports.
internal-enrichment/stairwell/src/connector/settings.py Pydantic/connectors-sdk settings models for connector + Stairwell config.
internal-enrichment/stairwell/src/connector/ip_enricher.py IP enrichment implementation (geo/cloud/asn/whois + note emission).
internal-enrichment/stairwell/src/connector/file_enricher.py File enrichment implementation (metadata, notes, variants, sightings, related IOCs).
internal-enrichment/stairwell/src/connector/enricher.py Dispatcher routing OpenCTI entity types to the correct enricher.
internal-enrichment/stairwell/src/connector/domain_enricher.py Domain enrichment implementation (DNS resolutions + whitelist + note emission).
internal-enrichment/stairwell/src/connector/connector.py OpenCTI connector wrapper (TLP gating + message processing + dispatch).
internal-enrichment/stairwell/src/connector/asn_enricher.py ASN enrichment implementation (WHOIS parsing + note emission).
internal-enrichment/stairwell/src/connector/init.py Package marker for connector module.
internal-enrichment/stairwell/src/config.yml.sample Sample YAML configuration for local runs.
internal-enrichment/stairwell/README.md Connector documentation (capabilities, configuration, behavior, install/test).
internal-enrichment/stairwell/entrypoint.sh Container entrypoint script.
internal-enrichment/stairwell/Dockerfile Container build definition for the connector.
internal-enrichment/stairwell/docker-compose.yml Example compose service definition for deployment.
internal-enrichment/stairwell/.env.test.sample Sample env file for local manual testing.
internal-enrichment/stairwell/.dockerignore Docker ignore rules for packaging.
internal-enrichment/stairwell/metadata/connector_manifest.json Connector metadata manifest for the OpenCTI connectors catalog.

Comment on lines +413 to +418
make_relationship(
source_id=source_entity_id,
target_id=sco["id"],
relationship_type="derived-from",
tlp=self.tlp,
)
Comment on lines +26 to +27
def stix_id(stix_type: str, seed: str) -> str:
return f"{stix_type}--{uuid.uuid5(_STIX_NAMESPACE, seed)}"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks — this is intentional. We mint deterministic UUIDv5 SCO IDs from the STIX 2.1 namespace so re-enrichment and cross-run dedup stay stable. OpenCTI recomputes each observable's canonical standard_id from its value on ingest, so duplicates by value shouldn't occur regardless of the incoming id. We're confirming that in live end-to-end testing on 6.8.x; if any duplication surfaces, we'll switch SCO ID generation to STIX2 canonicalization (per the rst-whois example) before requesting final review.

Comment thread internal-enrichment/stairwell/README.md Outdated
| Connector name | `connector.name` | `CONNECTOR_NAME` | yes | `Stairwell` | Display name in OpenCTI |
| Connector scope | `connector.scope` | `CONNECTOR_SCOPE` | yes | `StixFile,Domain-Name,IPv4-Addr,IPv6-Addr,Autonomous-System` | Observable types this connector handles |
| Auto enrich | `connector.auto` | `CONNECTOR_AUTO` | no | `false` | Enrich every newly-created in-scope observable |
| Log level | `connector.log_level` | `CONNECTOR_LOG_LEVEL` | no | `info` | `debug`, `info`, `warn`, `error` |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla:pending CLA signature required. community Contribution from the community.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(stairwell-enrichment): add internal-enrichment connector

4 participants