posture

package
v0.5.9 Latest Latest
Warning

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

Go to latest
Published: Sep 8, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultQueryPrefix = "osctrl:posture:"

DefaultQueryPrefix identifies scheduled queries whose result logs should be ingested as posture data by default.

Recommended practice: set the osquery schedule interval for posture queries to once per day (86400 seconds). Posture data — installed packages, users, disk encryption state — changes infrequently, and daily collection is sufficient for compliance audits without overloading agents or the logging pipeline.

View Source
const UptimeCategory = "uptime"

Variables

View Source
var QueryPrefix = DefaultQueryPrefix

QueryPrefix is the active posture query prefix. It is configured once at TLS startup. Empty disables posture ingestion.

View Source
var SeverityWeight = map[Severity]int{
	SeverityCritical: 30,
	SeverityHigh:     20,
	SeverityMedium:   10,
	SeverityLow:      5,
}

SeverityWeight converts severity to risk points.

Functions

func IsPostureQuery

func IsPostureQuery(name string) bool

IsPostureQuery returns true if the query name starts with the posture prefix.

func ParseUptime

func ParseUptime(record NodePosture) (*types.NodeUptime, error)

ParseUptime converts the latest uptime posture result into node metadata.

func PostureCategory

func PostureCategory(name string) string

PostureCategory extracts the category name from a posture query name. e.g. "osctrl:posture:packages" → "packages"

func RiskLevelFromScore

func RiskLevelFromScore(score int) string

RiskLevelFromScore converts a normalized score to a risk level.

func SetPrefix

func SetPrefix(prefix string)

SetPrefix sets the active posture query prefix.

func SummaryFromRecords

func SummaryFromRecords(records []NodePosture) *types.NodePostureSummary

Types

type CheckPatch added in v0.5.7

type CheckPatch struct {
	ProfileID          *string `json:"profile_id,omitempty"`
	ProfileName        *string `json:"profile_name,omitempty"`
	ProfileDescription *string `json:"profile_description,omitempty"`
	ProfilePlatform    *string `json:"profile_platform,omitempty"`
	Category           *string `json:"category,omitempty"`
	Name               *string `json:"name,omitempty"`
	Description        *string `json:"description,omitempty"`
	QueryName          *string `json:"query_name,omitempty"`
	Query              *string `json:"query,omitempty"`
	Interval           *int    `json:"interval,omitempty"`
	Platform           *string `json:"platform,omitempty"`
	Snapshot           *bool   `json:"snapshot,omitempty"`
	Enabled            *bool   `json:"enabled,omitempty"`
	ScoringRule        *string `json:"scoring_rule,omitempty"`
	ControlID          *string `json:"control_id,omitempty"`
	Framework          *string `json:"framework,omitempty"`
	Severity           *string `json:"severity,omitempty"`
	Weight             *int    `json:"weight,omitempty"`
}

CheckPatch is the small PATCH/POST body used by the API. Pointer fields let PATCH distinguish "unset" from zero values.

type ControlResult

type ControlResult struct {
	Category    string    `json:"category"`   // posture category the evidence came from
	ControlID   string    `json:"control_id"` // e.g. "A.8.24" or "CC6.6"
	Framework   Framework `json:"framework"`
	Title       string    `json:"title"`
	Description string    `json:"description"`
	Status      string    `json:"status"` // "pass", "warn", "fail"
	Severity    Severity  `json:"severity"`
	Score       int       `json:"score"` // 0 = pass, otherwise earned risk points
	// MaxScore is the risk points this control would contribute if it
	// failed outright (its weight). A passing control still reports this so
	// callers can renormalize the total after excluding controls — e.g. the
	// SPA's "what if I ignore this check" recompute — without needing the
	// evaluation rules themselves.
	MaxScore int    `json:"max_score"`
	Detail   string `json:"detail"` // human-readable explanation
}

ControlResult is the evaluation outcome for a single control.

type FleetCategorySummary

type FleetCategorySummary struct {
	Category  string `json:"category"`
	NodeCount int    `json:"node_count"`
	TotalRows int    `json:"total_rows"`
}

FleetCategorySummary is a per-category summary across all nodes in an environment.

type Framework

type Framework string

Framework is the compliance framework a control belongs to.

const (
	FrameworkSOC2     Framework = "SOC2"
	FrameworkISO27001 Framework = "ISO27001"
)

type NodePosture

type NodePosture struct {
	ID          uint      `gorm:"primarykey" json:"id"`
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
	NodeUUID    string    `gorm:"type:varchar(36);uniqueIndex:idx_posture_node_category" json:"node_uuid"`
	Environment string    `gorm:"index:idx_posture_env" json:"environment"`
	Category    string    `gorm:"uniqueIndex:idx_posture_node_category;type:varchar(64)" json:"category"`
	// QueryName is the full osquery scheduled-query name including prefix.
	QueryName string `gorm:"type:varchar(255)" json:"query_name"`
	// RowCount is the number of rows in the result (e.g. 3 packages, 5 users).
	RowCount int `json:"row_count"`
	// Summary is a compact JSON snapshot of the result data. For small
	// results this is the full columns array; for large results it's
	// truncated to the first 100 rows to keep the record manageable.
	Summary string `gorm:"type:text" json:"summary"`
	// Snapshot is the raw columns JSON from the latest result, capped at
	// 256KB. Used for detail views and compatibility with existing posture data.
	Snapshot string `gorm:"type:text" json:"-"`
	// FirstSeen is when this category was first observed for this node.
	FirstSeen time.Time `json:"first_seen"`
	LastSeen  time.Time `gorm:"index" json:"last_seen"`
}

NodePosture stores the latest snapshot of a single posture category for one node. Updated (upserted) every time a matching result log arrives.

func (NodePosture) TableName

func (NodePosture) TableName() string

TableName overrides the default table name.

type PostureCheck added in v0.5.7

type PostureCheck struct {
	ID                 uint      `gorm:"primarykey" json:"id"`
	CreatedAt          time.Time `json:"created_at"`
	UpdatedAt          time.Time `json:"updated_at"`
	ProfileID          string    `gorm:"type:varchar(64);uniqueIndex:idx_posture_check_profile_category" json:"profile_id"`
	ProfileName        string    `gorm:"type:varchar(255)" json:"profile_name"`
	ProfileDescription string    `gorm:"type:text" json:"profile_description"`
	ProfilePlatform    string    `gorm:"type:varchar(64)" json:"profile_platform"`
	Category           string    `gorm:"type:varchar(64);uniqueIndex:idx_posture_check_profile_category;index" json:"category"`
	Name               string    `gorm:"type:varchar(255)" json:"name"`
	Description        string    `gorm:"type:text" json:"description"`
	QueryName          string    `gorm:"type:varchar(255)" json:"query_name"`
	Query              string    `gorm:"type:text" json:"query"`
	Interval           int       `json:"interval"`
	Platform           string    `gorm:"type:varchar(64)" json:"platform"`
	Snapshot           bool      `json:"snapshot"`
	Enabled            bool      `gorm:"index" json:"enabled"`
	ScoringRule        string    `gorm:"type:varchar(64);index" json:"scoring_rule"`
	ControlID          string    `gorm:"type:varchar(64)" json:"control_id"`
	Framework          Framework `gorm:"type:varchar(32)" json:"framework"`
	Severity           Severity  `gorm:"type:varchar(32)" json:"severity"`
	Weight             int       `json:"weight"`
}

PostureCheck is an admin-editable posture scheduled-query template. ScoringRule selects a built-in evaluator; no executable logic is stored.

func (PostureCheck) TableName added in v0.5.7

func (PostureCheck) TableName() string

type PostureManager

type PostureManager struct {
	DB *gorm.DB
}

PostureManager manages the node posture table.

func NewPostureManager

func NewPostureManager(db *gorm.DB) *PostureManager

NewPostureManager creates the manager and auto-migrates the table.

func (*PostureManager) AllProfiles added in v0.5.7

func (pm *PostureManager) AllProfiles() ([]PostureProfile, error)

func (*PostureManager) CreateCheck added in v0.5.7

func (pm *PostureManager) CreateCheck(patch CheckPatch) (*PostureCheck, error)

func (*PostureManager) DeleteCheck added in v0.5.7

func (pm *PostureManager) DeleteCheck(id uint) error

func (*PostureManager) GetByNode

func (pm *PostureManager) GetByNode(nodeUUID string) ([]NodePosture, error)

GetByNode returns all posture categories for a node, ordered by category.

func (*PostureManager) GetByNodeCategory

func (pm *PostureManager) GetByNodeCategory(nodeUUID, category string) (*NodePosture, error)

GetByNodeCategory returns a single posture category for a node.

func (*PostureManager) GetCheck added in v0.5.7

func (pm *PostureManager) GetCheck(id uint) (*PostureCheck, error)

func (*PostureManager) GetFleetSummary

func (pm *PostureManager) GetFleetSummary(environment string) ([]FleetCategorySummary, error)

GetFleetSummary returns per-category posture counts across all nodes in an environment.

func (*PostureManager) GetProfile added in v0.5.7

func (pm *PostureManager) GetProfile(id string) (*PostureProfile, error)

func (*PostureManager) GetSummaryByNode

func (pm *PostureManager) GetSummaryByNode(nodeUUID string) (*types.NodePostureSummary, error)

func (*PostureManager) GetSummaryByNodes

func (pm *PostureManager) GetSummaryByNodes(nodeUUIDs []string) (map[string]*types.NodePostureSummary, error)

func (*PostureManager) GetUptimeByNode

func (pm *PostureManager) GetUptimeByNode(nodeUUID string) (*types.NodeUptime, error)

func (*PostureManager) GetUptimeByNodes

func (pm *PostureManager) GetUptimeByNodes(nodeUUIDs []string) (map[string]*types.NodeUptime, error)

func (*PostureManager) IngestResult

func (pm *PostureManager) IngestResult(nodeUUID, environment, queryName string, columns json.RawMessage) error

IngestResult processes a single result log entry and upserts the posture record if the query name matches the posture prefix.

func (*PostureManager) ListChecks added in v0.5.7

func (pm *PostureManager) ListChecks() ([]PostureCheck, error)

func (*PostureManager) Score added in v0.5.7

func (pm *PostureManager) Score(records []NodePosture) (PostureScore, error)

func (*PostureManager) SeedDefaultChecks added in v0.5.7

func (pm *PostureManager) SeedDefaultChecks() error

func (*PostureManager) UpdateCheck added in v0.5.7

func (pm *PostureManager) UpdateCheck(id uint, patch CheckPatch) (*PostureCheck, error)

type PostureProfile

type PostureProfile struct {
	ID          string                  `json:"id"`
	Name        string                  `json:"name"`
	Description string                  `json:"description"`
	Platform    string                  `json:"platform"`
	Queries     map[string]ProfileQuery `json:"queries"`
}

PostureProfile is a named set of posture check queries that an operator can merge into an environment's schedule config. Each profile targets a specific node type and platform with checks tailored to that environment's compliance requirements.

func AllProfiles

func AllProfiles() []PostureProfile

AllProfiles returns every predefined posture profile, sorted by name.

func GetProfile

func GetProfile(id string) *PostureProfile

GetProfile returns a single profile by ID, or nil if not found.

func LinuxLaptopProfile

func LinuxLaptopProfile() PostureProfile

func LinuxServerProfile

func LinuxServerProfile() PostureProfile

func MacOSLaptopProfile

func MacOSLaptopProfile() PostureProfile

func WindowsLaptopProfile

func WindowsLaptopProfile() PostureProfile

func WindowsServerProfile

func WindowsServerProfile() PostureProfile

func (PostureProfile) ToScheduleEntries

func (p PostureProfile) ToScheduleEntries() (map[string]map[string]interface{}, error)

ToScheduleEntries converts a profile's queries into a JSON map suitable for merging into an environment's schedule config section.

func (PostureProfile) ToScheduleJSON

func (p PostureProfile) ToScheduleJSON() (string, error)

ToScheduleJSON returns the schedule entries as pretty-printed JSON.

type PostureScore

type PostureScore struct {
	NodeUUID   string          `json:"node_uuid"`
	Timestamp  time.Time       `json:"timestamp"`
	TotalScore int             `json:"total_score"` // 0-100 normalized, lower is better
	RiskLevel  string          `json:"risk_level"`  // "low", "medium", "high", "critical"
	Controls   []ControlResult `json:"controls"`
	PassCount  int             `json:"pass_count"`
	WarnCount  int             `json:"warn_count"`
	FailCount  int             `json:"fail_count"`
}

PostureScore is the aggregate risk assessment for a node.

type ProfileQuery

type ProfileQuery struct {
	QueryName string `json:"query_name,omitempty"`
	Query     string `json:"query"`
	Interval  int    `json:"interval"`
	Platform  string `json:"platform,omitempty"`
	Snapshot  bool   `json:"snapshot"`
}

ProfileQuery is a single scheduled query within a posture profile.

type ScoreCalculator

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

ScoreCalculator evaluates posture data against compliance controls.

func NewScoreCalculator

func NewScoreCalculator() *ScoreCalculator

NewScoreCalculator returns a calculator with all built-in rules.

func NewScoreCalculatorWithChecks added in v0.5.7

func NewScoreCalculatorWithChecks(checks []PostureCheck) *ScoreCalculator

NewScoreCalculatorWithChecks returns a calculator configured from enabled DB checks. Checks without a built-in ScoringRule still collect posture data but do not contribute to risk score.

func (*ScoreCalculator) Score

func (sc *ScoreCalculator) Score(records []NodePosture) PostureScore

Score evaluates all posture records and returns the aggregate score.

type ScoringRule

type ScoringRule struct {
	RuleKey string `json:"rule_key"`
	// Categories lists every posture category that can provide evidence
	// for this control. The rule is evaluated when at least one of them
	// has been collected; mutually exclusive sources (deb vs rpm) belong
	// in the same rule so an empty inapplicable source is not a finding.
	Categories  []string  `json:"categories"`
	ControlID   string    `json:"control_id"`
	Framework   Framework `json:"framework"`
	Title       string    `json:"title"`
	Description string    `json:"description"`
	Severity    Severity  `json:"severity"`
	Weight      int       `json:"weight"`
	// Evaluate receives the collected categories (only those present for
	// the node) with their parsed rows and returns (status, detail).
	// status is "pass", "warn", or "fail".
	Evaluate func(data map[string][]map[string]interface{}) (status, detail string)
}

ScoringRule defines how to evaluate one control from posture data.

type Severity

type Severity string

Severity is the risk weight of a failing control.

const (
	SeverityCritical Severity = "critical" // immediate risk, must fix
	SeverityHigh     Severity = "high"     // significant risk
	SeverityMedium   Severity = "medium"   // moderate risk
	SeverityLow      Severity = "low"      // minor risk
)

Jump to

Keyboard shortcuts

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