detectledger

package
v0.1.8 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package detectledger turns the agent-side detection engine's output (#422) into hash-chained, attributable evidence (#423). It does NOT own a chain: a detection is sealed into the SAME evidence spine as findings and judgments, with kind = "detection", so it is defensible in an audit and joins the correlation graph.

Boundary (enforced here and asserted by test): DETECTIONS are chained; raw telemetry is NOT. This package has no method that seals a detection.Event — only a detection.Detection becomes a chain link. Per-event chaining would collapse throughput and is deliberately impossible through this API.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AgentKeyResolver

type AgentKeyResolver interface {
	AgentPublicKey(ctx context.Context, agentID shared.ID) (ed25519.PublicKey, error)
}

AgentKeyResolver returns the enrolment public key for an agent (#408), used to verify a batch's signature. An agent with no known key cannot have its batches admitted — fail closed.

type EvidenceChain

type EvidenceChain interface {
	// Seal appends content under the given kind, bound to the engagement's chain head, and returns the
	// new link's id.
	Seal(ctx context.Context, engagementID shared.ID, kind string, content []byte, createdBy string) (shared.ID, error)
	// Verify checks the engagement's chain and returns a non-nil error (wrapping evidence.ErrChainBroken)
	// when it is broken, so a dependent report can be blocked.
	//
	// IMPORTANT for the composition-root bridge: evidence.Service.Verify returns (Report, error) and
	// signals a BROKEN chain via Report.Intact=false with a NIL error (the non-nil error is reserved for
	// I/O failures). A bridge must therefore inspect Report.Intact and synthesize an
	// evidence.ErrChainBroken-wrapping error itself — returning the raw error would report a tampered
	// chain as healthy. This contract exists precisely so that mistake cannot be made silently.
	Verify(ctx context.Context, engagementID shared.ID) error
}

EvidenceChain is the narrow slice of the evidence vault this package needs: seal a detection into the chain, and verify the chain. It is a consumer-side interface bridged to *evidence.Service at the composition root (like offensivepolicy's EvidenceSealer), so this package never depends on the concrete vault or the domain Evidence shape.

type IngestItem

type IngestItem struct {
	ID        shared.ID
	Detection detection.Detection
	AssetID   shared.ID
}

IngestItem is one detection in a batch together with the asset it was observed on (#423 requirement 5: a detection joins the asset model).

type IngestResult

type IngestResult struct {
	EngagementID  shared.ID
	SealedRecords []shared.ID
	EvidenceIDs   []shared.ID
	Skipped       []shared.ID // already-sealed detections skipped on an idempotent retry
	Gap           fleetagent.SequenceGap
}

IngestResult reports the outcome of ingesting a batch.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader is the read-only projection of the ledger, for the HTTP read routes. It needs only the record store — no chain, key resolver, or audit — so the read surface can be wired live before the agent batch-ingest transport is. The full Service handles the write (ingest/seal/expire) path.

func NewReader

func NewReader(records ports.DetectionRecordStore) (*Reader, error)

NewReader builds the read-only ledger view.

func (*Reader) Incidents

func (r *Reader) Incidents(ctx context.Context, engagementID shared.ID) ([]detection.Incident, error)

Incidents returns the incident rollup over the engagement's detections.

func (*Reader) ListDetections

func (r *Reader) ListDetections(ctx context.Context, engagementID shared.ID) ([]detection.Record, error)

ListDetections returns the engagement's non-expired detection records, tenant-scoped.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service ingests agent detection batches into the evidence ledger.

func NewService

func NewService(records ports.DetectionRecordStore, chain EvidenceChain, keys AgentKeyResolver, audit ports.AuditLogger, clock ports.Clock, ids ports.IDGenerator, retention time.Duration) (*Service, error)

NewService validates its dependencies. Every one is required: a ledger that cannot seal, resolve an agent key, persist, or audit is not producing attributable evidence.

func (*Service) Expire

func (s *Service) Expire(ctx context.Context, engagementID shared.ID, actor, reason string) (int, error)

Expire removes projection rows whose retention has elapsed, as an AUDITED action carrying the actor and reason. It never removes chain links (those are permanent) and never runs silently: deleting evidence without a trail is exactly what this project exists to prevent.

func (*Service) Incidents

func (s *Service) Incidents(ctx context.Context, engagementID shared.ID) ([]detection.Incident, error)

Incidents returns the incident-level rollup for an engagement. The rollup is a view: the individual attributable detections remain the ledger underneath.

func (*Service) Ingest

func (s *Service) Ingest(ctx context.Context, batch fleetagent.AgentBatch, items []IngestItem) (IngestResult, error)

Ingest admits one signed, sequenced agent batch: it verifies the signature, detects a sequence gap (reported as a potential loss, never silently accepted), seals each detection into the evidence chain as kind="detection", and persists the projection rows bound to their chain links and asset.

func (*Service) ListDetections

func (s *Service) ListDetections(ctx context.Context, engagementID shared.ID) ([]detection.Record, error)

ListDetections returns the engagement's (non-expired) detection records, tenant-scoped by the store.

func (*Service) VerifyChain

func (s *Service) VerifyChain(ctx context.Context, engagementID shared.ID) error

VerifyChain checks the engagement's evidence chain; a broken chain returns an error wrapping evidence.ErrChainBroken so the report that depends on it is blocked, exactly as any chain break is.

Jump to

Keyboard shortcuts

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