ioc

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 23, 2026 License: GPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package ioc — Indicators of Compromise.

An IOC is a tenant-scoped artefact (IP, domain, hash, URL, process name, user-agent) that has been observed in connection with a vulnerability/finding. At runtime, agents emit telemetry events; the correlator matches those events against the IOC catalogue and auto-reopens the originating finding when a hit occurs — the loop closure named "invariant B6" in the CTEM model.

The domain package defines the entity + the persistence contract only. Correlation logic and the runtime wire live in internal/app/ioc.

Index

Constants

This section is empty.

Variables

AllTypes is the canonical list — used for validation and iteration.

View Source
var ErrEmptyValue = errors.New("ioc: value required")

ErrEmptyValue is returned by NewIndicator when value is empty after normalization.

View Source
var ErrInvalidType = errors.New("ioc: invalid type")

ErrInvalidType is returned by NewIndicator when the type isn't one of the supported Type constants.

View Source
var ErrInvalidValueFormat = errors.New("ioc: value format doesn't match type")

ErrInvalidValueFormat is returned by NewIndicator when the value doesn't match the format implied by the type (e.g. "not-an-ip" submitted with type=ip). Without this check the catalogue would accept garbage that the correlator can never match, and attackers could pollute a tenant's catalogue with unbounded junk values.

Functions

func Normalize

func Normalize(t Type, value string) string

Normalize returns the match form for a given type. Kept exported so callers doing lookups (correlator) produce the same key the entity stores.

  • IP, domain, URL, user-agent → lower + trim.
  • file hash → lower + trim (hex case doesn't matter, but leave raw hex bytes alone).
  • process name → trim only (Windows process names are case-insensitive on disk, but keep the display form).

Types

type Candidate

type Candidate struct {
	Type       Type
	Normalized string
}

Candidate is a (type, normalized_value) pair the correlator extracts from a telemetry event and hands to the repo.

type Indicator

type Indicator struct {
	ID              shared.ID
	TenantID        shared.ID
	Type            Type
	Value           string // display value
	Normalized      string // matching value (lowercase, stripped)
	SourceFindingID *shared.ID
	Source          Source
	Active          bool
	Confidence      int // 0-100, default 75
	FirstSeenAt     time.Time
	LastSeenAt      time.Time
	CreatedAt       time.Time
	UpdatedAt       time.Time
}

Indicator is one IOC row. The correlator looks it up by (TenantID, Type, Normalized) — never by raw Value.

func NewIndicator

func NewIndicator(tenantID shared.ID, t Type, value string, src Source) (*Indicator, error)

NewIndicator validates + builds a new Indicator. Normalization is done here so the repo never has to care about input hygiene.

type Match

type Match struct {
	ID               shared.ID
	TenantID         shared.ID
	IOCID            shared.ID
	TelemetryEventID *shared.ID
	FindingID        *shared.ID
	Reopened         bool
	MatchedAt        time.Time
}

Match is the return shape of the correlator — one per IOC hit.

type Repository

type Repository interface {
	// Create inserts a new indicator. Duplicate key on
	// (tenant_id, type, normalized) should update last_seen_at only.
	Create(ctx context.Context, ind *Indicator) error
	// GetByID loads one. Tenant-scoped.
	GetByID(ctx context.Context, tenantID, id shared.ID) (*Indicator, error)
	// FindActiveByValues bulk-matches a set of (type, normalized)
	// candidates — this is the correlator's hot path.
	FindActiveByValues(ctx context.Context, tenantID shared.ID, candidates []Candidate) ([]*Indicator, error)
	// RecordMatch appends an ioc_matches row.
	RecordMatch(ctx context.Context, m Match) error
	// ListByTenant paginates IOC rows for the UI.
	ListByTenant(ctx context.Context, tenantID shared.ID, limit, offset int) ([]*Indicator, error)
	// Deactivate flips active=false on an IOC (soft delete).
	Deactivate(ctx context.Context, tenantID, id shared.ID) error
}

Repository is the persistence contract.

type Source

type Source string

Source describes where an indicator originated.

const (
	SourceScanFinding Source = "scan_finding"
	SourceThreatFeed  Source = "threat_feed"
	SourceManual      Source = "manual"
)

type Type

type Type string

Type enumerates the kinds of indicator currently supported.

const (
	TypeIP          Type = "ip"
	TypeDomain      Type = "domain"
	TypeURL         Type = "url"
	TypeFileHash    Type = "file_hash"
	TypeProcessName Type = "process_name"
	TypeUserAgent   Type = "user_agent"
)

func (Type) IsValid

func (t Type) IsValid() bool

IsValid reports whether the type is one of the supported values.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL