OCSF

License

Elixir library modelling the Open Cybersecurity Schema Framework (OCSF 1.8).

Build, validate, and serialize security events that are OCSF-compliant out of the box. Persistence-agnostic core with optional companion libraries for Postgres and ClickHouse sinks.

Why

Installation

# mix.exs
def deps do
  [
    {:ocsf, path: "../ocsf"}
  ]
end

When published to hex.pm:

{:ocsf, "~> 0.1"}

Quick start

Check the OCSF version

OCSF.version()
#=> "1.8.0"

Explore enums

OCSF.Category.name(3)
#=> :"Identity & Access Management"

OCSF.Class.name(3002)
#=> :Authentication

OCSF.Activity.label(3002, 1)
#=> :Logon

OCSF.Severity.name(1)
#=> :Informational

Build an Authentication event (M1 -- coming soon)

{:ok, event} =
  OCSF.Events.Authentication.logon(
    user: %{
      uid:        "018f19fe-6d4c-71c2-a84b-5d2d8c7f1e90",
      email_addr: "jane@example.com",
      org:        %{uid: "communitiz-app"}
    },
    http_request: %{url: "/oauth/token", http_method: "POST"},
    src_endpoint: %{ip: {10, 0, 0, 1}},
    status:        :Success,
    auth_protocol: :"OAUTH 2.0",
    severity:      :Informational,
    event_code_format: :default
  )

# Serialize to OCSF-compliant JSON
Jason.encode!(event)

Correlation across a flow

correlation_uid = OCSF.UUID.v7_string()

OCSF.Correlation.with(correlation_uid, fn ->
  # Every event created here gets the same correlation_uid
  emit_challenge_created(...)
  emit_challenge_answered(...)
  emit_logon_success(...)
end)

PII classification

OCSF.Classification.pii?(:contact)
#=> true

OCSF.Classification.default_policy(:contact)
#=> :deny

OCSF.User.__ocsf_fields__()
#=> [
#     uid:        [class: :identifier, erasable: false],
#     name:       [class: :identity,   erasable: true],
#     email_addr: [class: :contact,    erasable: true],
#     org:        [class: :tenant,     erasable: false],
#     type_id:    [class: :taxonomic,  erasable: false]
#   ]

Architecture

ocsf              structs, enums, validation, serialization, PII classification
                  runtime dep: jason, uuid_v7

ocsf_ecto         Ecto schema + Ecto.Type shims for Postgres
(optional)        deps: ecto_sql, postgrex

ocsf_clickhouse   Ecto schema + DDL helpers for ClickHouse
(optional)        deps: ecto_sql, ecto_ch

Events flow through three stages:

Emit              Build an %OCSF.Event{} via a class builder
    |
Redact            Apply sink policy: deny PII, transform network fields
    |
Write             Project to flat columns, bulk-insert via sink adapter

Core modules

Module Purpose
OCSF Facade -- version/0
OCSF.Category Category UID <-> name lookup
OCSF.Class Class UID <-> name lookup + category/1
OCSF.Activity Per-class activity ID <-> label
OCSF.Severity Severity ID <-> name
OCSF.Status Status ID <-> name
OCSF.StatusDetail Well-known status_detail strings per class
OCSF.AuthProtocol Auth protocol ID <-> name
OCSF.UUID UUIDv7 generation (delegates to uuid_v7)
OCSF.Correlation Process-dict correlation scope
OCSF.Classification Data class taxonomy + PII helpers

Nested object structs

Struct OCSF object
OCSF.MetadataMetadata
OCSF.UserUser
OCSF.OrganizationOrganization
OCSF.ProductProduct
OCSF.FeatureFeature
OCSF.HttpRequestHTTP Request
OCSF.NetworkEndpointNetwork Endpoint
OCSF.ActorActor
OCSF.ServiceService

Every struct exposes __ocsf_fields__/0 for PII classification metadata.

Supported OCSF classes

Class UID Category Status
Authentication 3002 Identity & Access Management v0 (current)
Account Change 3001 Identity & Access Management v1 (planned)
Authorization 3003 Identity & Access Management v1 (planned)
API Activity 6003 Application Activity v1 (planned)

Compliance model

Every field on every struct is tagged with a data class (:contact, :identity, :network, :credential, etc.). Sinks declare policies -- allow/deny rules per class with optional transforms (:truncate_v4_24, :hash_salted, :ua_parse_only).

Right-to-erasure (GDPR Art. 17): Postgres crypto-shreds via per-user AES key rotation. ClickHouse never stores erasable PII.

See OCSF.Classification for the full taxonomy.

OCSF version policy

One library release targets one OCSF version:

OCSF.version/0 returns the pinned version. Every emitted event carries metadata.version so stored rows identify which schema they conform to.

Naming conventions

The library uses __ (double underscore) as the universal segment separator for flat-projected column names, table prefixes, and index names:

Context Example
Table ocsf_event__logs
Column user__email_addr
Nested column user__org__uid
Index ocsf_event__logs__class__idx

Single _ only appears inside OCSF leaf segment names (email_addr, user_agent, class_uid).

Glossary

Authoritative definitions. All project documentation uses these terms verbatim.

Term Definition
Event One OCSF-compliant record (%OCSF.Event{}).
Class OCSF event class (e.g. 3002 = Authentication).
Category OCSF top-level grouping (e.g. 3 = Identity & Access Management).
Activity Class-scoped sub-type (e.g. Logon inside Authentication).
Metadata OCSF object carrying uid, version, product, event_code.
Nested object Structured sub-record (user, http_request, src_endpoint).
Flat projection__-joined column form (user.email_addr -> user__email_addr).
Sink Write-only event destination. Implements OCSF.Sink behaviour.
Policy Sink's allow/deny rules per data class + transforms.
Redaction Applying a policy to an event before writing.
Data class Semantic tag on a field (:identifier, :contact, :network, etc.).
PII Personally identifiable information; derived from data class.
Erasable Field subject to GDPR right-to-erasure (crypto-shreddable in Postgres).
Transform Function applied to a field before it reaches a sink.
Table prefix Configurable prefix for sink tables (default: ocsf_event__).
Table base Configurable suffix after prefix (default: logs). Full: ocsf_event__logs.
Correlation UIDmetadata.correlation_uid -- ties events in one business flow.
Trace UIDmetadata.trace_uid -- W3C/OTel distributed trace ID.
Observable OCSF typed reference in observables[] for SIEM pivoting.
Enrichment OCSF extension slot in enrichments[] for downstream processors.

Links

License

Apache-2.0