Connectors & Extensions
Relata does not fetch from external sources inside the database process. Per the ETL Boundary policy, this repository ships canonical type contracts + ingest trait impls + schema validators only — zero network dependencies in the signed binary. The actual fetching (polling, OAuth, vendor SDKs, webhooks) lives in datagrep, the external ETL tool that consumes these contracts, fetches from each source, and pushes governed rows into Relata. This keeps the binary SLSA-clean and credentials out of the DB process.
Relata's role at the boundary: map incoming data onto the identity model and build the governed graph — canonicalize → detect identities (SmartIngest) → build the graph → attach provenance (PROV-O) on every row.
The extension framework
Six extension kinds share one framework — one Manifest, one signing chain, one principal + ACL + audit contract:
| Kind | Role |
|---|---|
| Connector | Ingest from an external source |
| Detector | SmartIngest identity detection (two-phase) |
| Enricher | Augment rows from registered enrichment tables / rules |
| Scorer | Analytics scorers (social-media, behavioural — 13 ScorerOps) |
| Job | Scheduled / event-triggered maintenance + detection jobs |
| Report | Typed, signed analytical reports |
Three deployment modes:
| Mode | Runtime | Notes |
|---|---|---|
| builtin | Rust crate (relata-connector-<name>) | Compiled in; enabled via --enable-connector=<name> |
| WASM | Wasmtime Component Model + WASI 0.2 | Language-agnostic guest; typed WIT contract; capability-sandboxed; fuel/memory-capped (≤ 2× native overhead p50; ≤ 20% ingest throughput hit with 3 detectors) |
| external | gRPC / HTTP | Sidecar process |
The Connector trait
A typed Connector trait in relata-core::connectors enforces the bi-temporal + provenance contract at the connector boundary, preventing untagged rows:
pub trait Connector {
fn name(&self) -> &'static str;
fn schema(&self) -> HashMap<String, String>; // field → canonical-type label
fn ingest(&self, batch: ConnectorBatch) -> Result<Vec<String>, ConnectorError>;
}ConnectorBatch carries object_type, a BiTemporalRange, a ProvenanceRef, and Vec<ConnectorRow> — so connectors never need to know the object-store API. ConnectorError has three variants: InvalidSchema, IngestFailed, Io. The reference impls live in relata-connector-stub (NoopConnector for tests, DbtConnector which parses dbt NDJSON model export).
dbt adapter
The dbt path parses a pre-exported dbt NDJSON model and maps JSON values to CanonicalValue (DbtConnector::parse_ndjson), making it testable without a running dbt instance. Full dbt run integration ships in the Python sdks/python/dbt_relata/ package.
Migration connectors: relata import --from
Migrate an existing database straight into the governed identity fabric — no CSV export step. Every row lands through POST /ingest/bulk → governed_upsert_many, the same write path every protocol door uses, so SmartIngest identity detection, registered ingest pipelines, ACL, tenant-ownership, and audit logging all apply.
# Postgres is a real, wired connector
relata import --from postgres \
--dsn "postgresql://user:pass@localhost:5432/appdb" \
--table users --type Person \
--dry-run # prints ≤5 mapped rows, opens no write transaction| Source | Status |
|---|---|
postgres | Live — server-side cursor, streaming FETCH pages, type-faithful JSON (numeric/decimal kept as exact text), single-column PK → _pk |
csv / ndjson | Live — relata import --from csv --file <path> |
neo4j, mongo, clickhouse | Honest stubs — no driver wired; each prints the CSV/NDJSON export workaround and exits non-zero (never a silent no-op). Use the documented workaround today. |
Key v1 limitations: --type must name an already-registered governed type (no DDL); TLS is not wired (NoTls); quoted/mixed-case identifiers rejected; no relationship/FK import yet (one table → one governed type per invocation).
Connector catalog
~120 catalogued type contracts across telco, social, news, email, documents, threat-intel, cyber telemetry, cloud audit, financial/AML, blockchain, identity/KYC, geospatial, and streams. Three-tier status per entry:
- ✅ live — registered + fetches (
noop,dbt; MISP/TAXII/STIX bundle import viaPOST /import?format=stix) - 🟡 registered stub —
?connector=<name>resolves; returns a clearnot yet implemented(never a silent no-op); fetch lives in datagrep - 🔲 catalog spec — canonical type contract documented for datagrep; not yet registered
Highlights that are live in this repo (not through datagrep):
| Source | Door | Notes |
|---|---|---|
| CSV / NDJSON / JSON array | POST /ingest | Auto-detected by first byte |
| Kafka | KafkaIngestAdapter | Pure-Rust wire-protocol client (no rdkafka/unsafe) — see Ingestion |
| CDR | POST /ingest/cdr | Typed fast path for call-detail records — see Ingestion |
| STIX bundle | POST /import?format=stix | Threat-intel object import |
| MISP | relata misp-pull | Pulls via MISP restSearch API |
| TAXII 2.1 | relata taxii-poll | Polls a collection's STIX objects |
| Sigma rule import | relata import-sigma | Detection-rule import |
| Sanctions pull | relata pull-ioc | OFAC/UN/EU/OFSI/MEA/RBI/OpenSanctions |
The full catalog (telco IPDR/tower-dump/SMS/EDR, OSINT 13, FHIR R4, AIS stream, FININT 40, cloud audit, cyber telemetry, etc.) is documented as canonical type contracts in the source repo's connector catalog. For sources not in the catalog, author a custom connector as a relata-connector-<name> crate implementing Connector.
Ontology packs (domain packs)
Packs bundle a domain's ontology types, detectors, jobs, reports, and detection rules into a signed, versioned unit. The repo ships ~20 domain packs + ~25 jurisdiction packs; the portal's use-cases map to these:
| Pack | Domain |
|---|---|
finint | Financial intelligence / AML (sanctions, PEP, wires, crypto) |
cyber | Cyber threat intel, C2/beacon detection |
counter_terror | Counter-terrorism pattern detection |
counter_intel | Counter-intelligence |
lea | Law-enforcement telco (CDR, IPDR, tower dump) |
maritime | AIS, dark-fleet detection |
narcotics | Narcotics supply-chain patterns |
border | Border-crossing analysis |
defense | Defense / military intelligence |
geopolitics, gcc_mena, india, health, aml | Regional / sectoral |
jurisdiction-<cc> (25) | Per-jurisdiction legal type sets |
relata-pack-stub demonstrates the pack layout for authoring new packs.
Field-mapping convention (all connectors)
Every connector follows the same canonicalization recipe:
- Parse the source field to its native type.
- Validate against the canonical type's checksum/format/registry (76 canonical types — email, IBAN, MMSI, VIN, IMEI…).
- Canonicalize to the binary representation (uint32 for IPv4, E.164 uint64 for phone, S2 cell for geo…).
- Attach provenance —
(source_connector_id, file_or_batch_id, record_offset, observed_at, recorded_at). - Index in
IdentityIndexwithobserved_in = (object_type, object_id, property_path). - Quarantine on validation failure (strict reject / permissive auto-create / auto-map suggest).
See also
- Ingestion & SmartIngest — Kafka, CDR, ingest pipelines,
relata import - Identity — canonical types and entity resolution
- Jobs, Workflows & Detection — the Job/Report extension kinds
- SQL Reference —
DETECT_IDENTITIES,RESOLVE_IDENTITY, domain TVFs