rulepack

package
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package rulepack evaluates deterministic release evidence for signed detection RulePacks.

Index

Constants

View Source
const (
	// GateEvidenceAttestationContext domain-separates RulePack release evidence from the repository's
	// evidence/audit chain-head attestations even when the same infrastructure signer key is reused.
	GateEvidenceAttestationContext = "synapse-rulepack-gate-evidence:v1"
)

Variables

This section is empty.

Functions

func Advance

Advance recomputes release evidence at the transition boundary instead of trusting a caller-supplied Report. Candidate->canary needs all pre-canary gates and canary->promoted needs the full release gate. The deployment embedded in GateInput is overwritten with d so evidence cannot be evaluated against a healthier deployment than the one actually being transitioned. Rollback deliberately bypasses gate recomputation: if signed rollback metadata is valid, safety must remain available even when evidence is malformed or the rollout is incompatible.

func CollectPurpleEvidence

func CollectPurpleEvidence(ctx context.Context, reader PurpleReader, request PurpleRequest) ([]purplecoverage.Coverage, error)

CollectPurpleEvidence loads measured purple coverage and returns only rows from the requested run. Empty or cross-scope evidence fails closed: claimed ATT&CK coverage cannot be inferred from a missing run, another engagement, or a row without the asset on which the emulation was measured.

Types

type EvidenceCollector

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

EvidenceCollector obtains the release evidence whose provenance matters from the existing authoritative seams, then attests to the deterministic envelope. It performs no persistence itself.

func NewEvidenceCollector

func NewEvidenceCollector(hunter TelemetryHunter, purple PurpleReader, signer GateEvidenceSigner) (*EvidenceCollector, error)

NewEvidenceCollector validates the release-evidence dependencies.

func (*EvidenceCollector) Collect

Collect obtains retro-hunt and purple evidence from their authoritative services and returns an attested envelope. A valid-but-failing release (for example a real purple gap) is still attestable; malformed evidence is refused before it can acquire provenance.

type Failure

type Failure struct {
	Code   string `json:"code"`
	Detail string `json:"detail"`
}

Failure is a stable machine-readable reason one stage did not pass.

type GateEvidenceRequest

type GateEvidenceRequest struct {
	Deployment rulepackdomain.RulePackDeployment `json:"deployment"`
	Policy     GatePolicy                        `json:"policy"`
	Costs      []RuleCostObservation             `json:"costs"`
	RetroCases []RetroCase                       `json:"retro_cases"`
	Purple     PurpleRequest                     `json:"purple_request"`
	Evaluation QualitySample                     `json:"evaluation"`
	Canary     *QualitySample                    `json:"canary,omitempty"`
	Production *QualitySample                    `json:"production,omitempty"`
}

GateEvidenceRequest contains operator-owned policy/measurements plus selectors for evidence that must be collected from authoritative telemetry and purple-coverage services. Callers cannot inject raw RetroEvidence or purplecoverage.Coverage into this boundary.

type GateEvidenceSigner

type GateEvidenceSigner interface {
	Sign(ctx context.Context, head string) (evidence.Attestation, error)
}

GateEvidenceSigner is satisfied by the existing infrastructure/signing.Ed25519Signer. The composition root must configure it with GateEvidenceAttestationContext before giving it to the collector.

type GateInput

type GateInput struct {
	Deployment rulepackdomain.RulePackDeployment `json:"deployment"`
	Policy     GatePolicy                        `json:"policy"`
	Costs      []RuleCostObservation             `json:"costs"`
	Retro      []RetroEvidence                   `json:"retro"`
	Purple     []purplecoverage.Coverage         `json:"purple"`
	Evaluation QualitySample                     `json:"evaluation"`
	Canary     *QualitySample                    `json:"canary,omitempty"`
	Production *QualitySample                    `json:"production,omitempty"`
}

GateInput is all deterministic evidence needed for one RulePack release evaluation. Canary and Production may be omitted while a candidate is only seeking admission to the canary stage.

func VerifyGateEvidence

func VerifyGateEvidence(s SignedGateEvidence, p rulepackdomain.RulePack, trustedPub ed25519.PublicKey) (GateInput, error)

VerifyGateEvidence verifies that s was produced by a trusted evidence collector for this exact RulePack. The attestation's embedded public key is never self-authorizing: it must byte-match the externally pinned trustedPub supplied by the caller.

type GatePolicy

type GatePolicy struct {
	MinimumPrecisionBPS                    int   `json:"minimum_precision_bps"`
	MaximumFalsePositiveRateBPS            int   `json:"maximum_false_positive_rate_bps"`
	MinimumAnalystDispositionRateBPS       int   `json:"minimum_analyst_disposition_rate_bps"`
	MinimumRequiredFieldAvailabilityBPS    int   `json:"minimum_required_field_availability_bps"`
	MinimumATTACKCoverageBPS               int   `json:"minimum_attack_coverage_bps"`
	MaximumCanaryDetectionsPerHostDayMilli int64 `json:"maximum_canary_detections_per_host_day_milli"`
	MaximumProdDetectionsPerHostDayMilli   int64 `json:"maximum_prod_detections_per_host_day_milli"`
	MinimumReviewedDetections              int64 `json:"minimum_reviewed_detections"`
	MinimumHostDays                        int64 `json:"minimum_host_days"`
}

GatePolicy is operator-owned release policy. Rates are integer basis points to keep CI decisions deterministic; detections/host-day is represented in milli-detections to avoid floating point.

func (GatePolicy) Validate

func (p GatePolicy) Validate() error

Validate rejects ambiguous release policy values.

type PurpleReader

type PurpleReader interface {
	Trend(ctx context.Context, engagementID shared.ID) ([]purplecoverage.Coverage, error)
}

PurpleReader is satisfied by purplecoverage.Service and keeps the release gate coupled only to the existing usecase seam, not to a persistence adapter.

type PurpleRequest

type PurpleRequest struct {
	EngagementID shared.ID `json:"engagement_id"`
	RunID        shared.ID `json:"run_id"`
}

PurpleRequest selects the exact emulation run whose measured coverage is release evidence.

type QualityMetrics

type QualityMetrics struct {
	Detections                   int64 `json:"detections"`
	ReviewedDetections           int64 `json:"reviewed_detections"`
	TruePositives                int64 `json:"true_positives"`
	FalsePositives               int64 `json:"false_positives"`
	SuppressedDetections         int64 `json:"suppressed_detections"`
	HostDays                     int64 `json:"host_days"`
	PrecisionBPS                 int   `json:"precision_bps"`
	FalsePositiveRateBPS         int   `json:"false_positive_rate_bps"`
	SuppressionRateBPS           int   `json:"suppression_rate_bps"`
	AnalystDispositionRateBPS    int   `json:"analyst_disposition_rate_bps"`
	RequiredFieldAvailabilityBPS int   `json:"required_field_availability_bps"`
	DetectionsPerHostDayMilli    int64 `json:"detections_per_host_day_milli"`
}

QualityMetrics is the deterministic metric surface #630 emits for CI and release review.

type QualitySample

type QualitySample struct {
	Detections           int64             `json:"detections"`
	TruePositives        int64             `json:"true_positives"`
	FalsePositives       int64             `json:"false_positives"`
	SuppressedDetections int64             `json:"suppressed_detections"`
	HostDays             int64             `json:"host_days"`
	AvailableFields      []detection.Field `json:"available_fields"`
}

QualitySample is exact labelled/runtime evidence used to compute detection-quality metrics. Detections are emitted detections; SuppressedDetections are candidates suppressed before emission. True/false positives are analyst dispositions over emitted detections and therefore must not exceed Detections.

type Report

type Report struct {
	PackID            string                `json:"pack_id"`
	PackVersion       int                   `json:"pack_version"`
	PackDigest        string                `json:"pack_digest"`
	PreCanaryPassed   bool                  `json:"pre_canary_passed"`
	CanaryPassed      bool                  `json:"canary_passed"`
	Passed            bool                  `json:"passed"`
	Stages            []StageResult         `json:"stages"`
	Costs             []RuleCostObservation `json:"costs"`
	EvaluationMetrics QualityMetrics        `json:"evaluation_metrics"`
	CanaryMetrics     *QualityMetrics       `json:"canary_metrics,omitempty"`
	ProductionMetrics *QualityMetrics       `json:"production_metrics,omitempty"`
	ATTACKCoverageBPS int                   `json:"attack_coverage_bps"`
}

Report is deterministic CI evidence. PreCanaryPassed admits candidate->canary, while Passed requires both canary and production metrics and is required for canary->promoted.

func Evaluate

func Evaluate(p rulepackdomain.RulePack, in GateInput) (Report, error)

Evaluate runs every release stage deterministically. A malformed pack, policy, or evidence object is an error; valid evidence that misses a threshold produces a Report with Pass=false and explicit reasons.

type RetroCase

type RetroCase struct {
	RuleID string          `json:"rule_id"`
	Query  ports.HuntQuery `json:"query"`
}

RetroCase identifies the bounded telemetry window used to prove one candidate rule can be retro-run.

type RetroEvidence

type RetroEvidence struct {
	RuleID        string `json:"rule_id"`
	ContextEvents int    `json:"context_events"`
	MatchedEvents int    `json:"matched_events"`
	Complete      bool   `json:"complete"`
	Sampled       bool   `json:"sampled"`
	SequenceGaps  int    `json:"sequence_gaps"`
	Losses        int    `json:"losses"`
}

RetroEvidence proves one candidate rule was evaluated against a telemetry window from the existing telemetry hunt seam. Complete, unsampled evidence is required for a release claim.

func CollectRetroEvidence

func CollectRetroEvidence(ctx context.Context, p rulepackdomain.RulePack, hunter TelemetryHunter, cases []RetroCase) ([]RetroEvidence, error)

CollectRetroEvidence evaluates each candidate rule over its requested stored-telemetry window. Exactly one case per RulePack rule is required, making missing retro coverage explicit rather than silently omitting a rule from the release gate.

type RetroQueryProvenance

type RetroQueryProvenance struct {
	RuleID  string          `json:"rule_id"`
	HostID  shared.ID       `json:"host_id"`
	AssetID shared.ID       `json:"asset_id,omitempty"`
	Class   detection.Class `json:"class"`
	Since   time.Time       `json:"since"`
	Until   time.Time       `json:"until"`
	Limit   int             `json:"limit"`
}

RetroQueryProvenance records the exact bounded telemetry selector used to produce one rule's retro evidence. The gate attestation binds these selectors alongside the aggregate result so a later release review can identify and reproduce the exact host/class/time window that was evaluated.

type RuleCostObservation

type RuleCostObservation struct {
	RuleID              string `json:"rule_id"`
	LatencyMicros       int64  `json:"latency_micros"`
	CPUMicrosPerHostDay int64  `json:"cpu_micros_per_host_day"`
}

RuleCostObservation is measured release evidence for one rule. It is compared to the signed RulePack's ExpectedCost budget; the gate does not benchmark wall-clock time itself.

type SignedGateEvidence

type SignedGateEvidence struct {
	PackID       string                 `json:"pack_id"`
	PackVersion  int                    `json:"pack_version"`
	PackDigest   string                 `json:"pack_digest"`
	RetroQueries []RetroQueryProvenance `json:"retro_queries"`
	Input        GateInput              `json:"input"`
	Attestation  evidence.Attestation   `json:"attestation"`
}

SignedGateEvidence is the immutable release-evidence envelope consumed by synapse-cli rulepack gate. Its attestation covers the exact RulePack identity, the bounded retro-hunt selectors, and canonical GateInput; verification pins the evidence producer key externally, independently of the RulePack content-signing key.

type Stage

type Stage string

Stage is one ordered RulePack release gate.

const (
	StageCompatibility  Stage = "compatibility"
	StagePositiveReplay Stage = "positive_replay"
	StageNegativeReplay Stage = "negative_replay"
	StagePerformance    Stage = "performance"
	StageRetroHunt      Stage = "retro_hunt"
	StageEmulation      Stage = "emulation"
	StageFPBudget       Stage = "false_positive_budget"
	StageCanary         Stage = "canary_metrics"
	StageProduction     Stage = "production_metrics"
)

type StageResult

type StageResult struct {
	Stage    Stage     `json:"stage"`
	Pass     bool      `json:"pass"`
	Failures []Failure `json:"failures,omitempty"`
}

StageResult records one gate's outcome in fixed release order.

type TelemetryHunter

type TelemetryHunter interface {
	Hunt(ctx context.Context, q ports.HuntQuery) (ports.HuntResult, error)
}

TelemetryHunter is satisfied by fleet/telemetry.Service. The candidate RulePack rule is evaluated over the returned window here rather than via telemetry.Service.RetroRunRule, because that existing helper intentionally re-runs the currently shipped detection catalogue and could false-green a candidate rule.

Jump to

Keyboard shortcuts

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