module

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: 5 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EventCategorySystem      = "system"
	EventCategoryAsset       = "asset"
	EventCategoryScan        = "scan"
	EventCategoryFinding     = "finding"
	EventCategoryExposure    = "exposure"
	EventCategoryCredential  = "credential"
	EventCategoryPentest     = "pentest"
	EventCategoryRemediation = "remediation"
	EventCategoryComponent   = "component"
	EventCategoryThreatIntel = "threat_intel"
)

Known event type categories.

View Source
const (
	ModuleCategoryCore       = "core"
	ModuleCategorySecurity   = "security"
	ModuleCategoryPlatform   = "platform"
	ModuleCategoryCompliance = "compliance"
	ModuleCategoryEnterprise = "enterprise"
)

ModuleCategory constants

View Source
const (
	// Core
	ModuleDashboard = "dashboard"
	ModuleAssets    = "assets"
	ModuleFindings  = "findings"
	ModuleScans     = "scans"

	// Discovery
	ModuleCredentials     = "credentials"
	ModuleComponents      = "components"
	ModuleBranches        = "branches"
	ModuleVulnerabilities = "vulnerabilities"

	// Prioritization
	ModuleThreatIntel = "threat_intel"
	ModuleExposures   = "exposures"
	ModuleAITriage    = "ai_triage"
	ModuleSLA         = "sla"

	// Validation
	ModulePentest          = "pentest"
	ModuleAttackSimulation = "attack_simulation"
	ModuleControlTesting   = "control_testing"

	// Compliance
	// Seeded by migration 000105_compliance_module_seed.up.sql.
	// User-facing (toggleable from Settings → Modules) and gated by
	// the compliance:frameworks:read permission.
	ModuleCompliance = "compliance"

	// Mobilization
	ModuleRemediation  = "remediation"
	ModuleSuppressions = "suppressions"
	ModulePolicies     = "policies"

	// Insights
	ModuleReports = "reports"
	ModuleAudit   = "audit"

	// Settings
	ModuleIntegrations         = "integrations"
	ModuleAgents               = "agents"
	ModuleTeam                 = "team"
	ModuleGroups               = "groups"
	ModuleRoles                = "roles"
	ModuleSettings             = "settings"
	ModuleAPIKeys              = "api_keys"
	ModuleWebhooks             = "webhooks"
	ModuleNotificationSettings = "notification_settings"

	// Data
	ModuleSources = "sources"
	ModuleSecrets = "secrets"
	ModuleScope   = "scope"

	// Operations
	ModulePipelines    = "pipelines"
	ModuleTools        = "tools"
	ModuleCommands     = "commands"
	ModuleScanProfiles = "scan_profiles"
	ModuleIOCs         = "iocs"

	// Scoping (CTEM) — seeded by migration 000161.
	ModuleAttackSurface    = "attack_surface"
	ModuleScopeConfig      = "scope_config"
	ModuleBusinessServices = "business_services"
	ModuleCTEMCycles       = "ctem_cycles"
	ModuleAttackerProfiles = "attacker_profiles"
	ModuleRelationships    = "relationships"

	// Prioritisation (CTEM) — seeded by migration 000161.
	ModulePriorityRules  = "priority_rules"
	ModuleRiskAnalysis   = "risk_analysis"
	ModuleBusinessImpact = "business_impact"
	ModuleRiskScoring    = "risk_scoring"

	// Validation — seeded by migration 000161.
	ModuleCompensatingControls = "compensating_controls"

	// Mobilisation — seeded by migration 000161.
	ModuleWorkflows        = "workflows"
	ModuleRemediationTasks = "remediation_tasks"

	// Insights — seeded by migration 000161.
	ModuleCTEMMaturity     = "ctem_maturity"
	ModuleExecutiveSummary = "executive_summary"
	ModuleMITRECoverage    = "mitre_coverage"
	ModuleSBOMExport       = "sbom_export"

	// Settings — seeded by migration 000161.
	ModuleScannerTemplates = "scanner_templates"
	ModuleTemplateSources  = "template_sources"
	ModuleScanPipelines    = "scan_pipelines"
)

Well-known module IDs (top-level modules)

View Source
const (
	ModuleIntegrationsSCM           = "integrations.scm"
	ModuleIntegrationsNotifications = "integrations.notifications"
	ModuleIntegrationsWebhooks      = "integrations.webhooks"
	ModuleIntegrationsAPI           = "integrations.api"
	ModuleIntegrationsPipelines     = "integrations.pipelines"
	ModuleIntegrationsTicketing     = "integrations.ticketing"
	ModuleIntegrationsSIEM          = "integrations.siem"
)

Integration sub-module IDs (children of ModuleIntegrations)

View Source
const (
	ModuleAITriageBulk          = "ai_triage.bulk"           // Bulk triage operations
	ModuleAITriageAuto          = "ai_triage.auto"           // Auto-triage on finding creation
	ModuleAITriageWorkflow      = "ai_triage.workflow"       // Workflow triggers and actions
	ModuleAITriageBYOK          = "ai_triage.byok"           // Bring Your Own Key mode
	ModuleAITriageAgent         = "ai_triage.agent"          // Self-hosted Agent mode
	ModuleAITriageCustomPrompts = "ai_triage.custom_prompts" // Custom prompt templates
)

AI Triage sub-module IDs (children of ModuleAITriage)

View Source
const (
	AITriageLimitMonthlyTokens = "monthly_token_limit" // Monthly token limit (int64, -1 = unlimited)
)

AI Triage limit keys for PlanModule.Limits

View Source
const DefaultPresetID = "ctem_full"

DefaultPresetID is the preset applied when a tenant is created without an explicit choice. "ctem_full" keeps the prior behaviour (all modules on) so existing flows don't regress.

View Source
const SubModuleSeparator = "."

SubModuleSeparator is the separator used in sub-module IDs (e.g., "integrations.scm").

View Source
const SubModuleSlugSeparator = "-"

SubModuleSlugSeparator is the separator used in sub-module slugs (e.g., "integrations-scm").

Variables

View Source
var (
	ErrPlanNotFound               = fmt.Errorf("%w: plan not found", shared.ErrNotFound)
	ErrPlanSlugExists             = fmt.Errorf("%w: plan slug already exists", shared.ErrConflict)
	ErrModuleNotFound             = fmt.Errorf("%w: module not found", shared.ErrNotFound)
	ErrEventTypeNotFound          = fmt.Errorf("%w: event type not found", shared.ErrNotFound)
	ErrSubscriptionNotFound       = fmt.Errorf("%w: subscription not found", shared.ErrNotFound)
	ErrInvalidPlanID              = fmt.Errorf("%w: invalid plan ID format", shared.ErrValidation)
	ErrInvalidModuleID            = fmt.Errorf("%w: invalid module ID format", shared.ErrValidation)
	ErrInvalidSubModuleID         = fmt.Errorf("%w: invalid sub-module ID format", shared.ErrValidation)
	ErrCoreModuleCannotBeDisabled = fmt.Errorf("%w: core module cannot be disabled", shared.ErrValidation)
	ErrModuleNotAvailable         = fmt.Errorf("%w: module is not available", shared.ErrValidation)
)

Domain errors.

View Source
var CategoryDisplayNames = map[string]string{
	EventCategorySystem:      "System",
	EventCategoryAsset:       "Assets",
	EventCategoryScan:        "Scans",
	EventCategoryFinding:     "Findings",
	EventCategoryExposure:    "Exposures",
	EventCategoryCredential:  "Credentials",
	EventCategoryPentest:     "Penetration Testing",
	EventCategoryRemediation: "Remediation",
	EventCategoryComponent:   "Components",
	EventCategoryThreatIntel: "Threat Intelligence",
}

CategoryDisplayNames maps category IDs to display names.

CoreModuleIDs defines modules that are essential for platform operation and cannot be disabled by tenant admins.

View Source
var MandatoryModuleIDs = map[string]bool{
	"agents":                     true,
	"notification_settings":      true,
	"integrations":               true,
	"integrations.notifications": true,
	"groups":                     true,
	"api_keys":                   true,
}

MandatoryModuleIDs lists modules every preset must include — "operational essentials" that any persona needs regardless of their security workflow choice. Distinct from CoreModuleIDs (which the platform forbids disabling at all): mandatory modules CAN be disabled by an admin post-apply if they really know what they're doing, but presets always opt them in by default.

Why each one (cross-checked against the actual ingestion pipeline, not just the module name):

  • agents → DATA INGESTION GATEWAY. Every collector / scanner / SBOM tool POSTs data through /api/v1/agent/ingest, authenticated by an agent API key. Without `agents` enabled, the tenant cannot register collectors, cannot receive scanner output, cannot ingest cloud asset data via push collectors. Architecturally this is more important than most "feature" modules because disabling it severs the tenant from any external data source that uses the modern push model.

  • notification_settings → every org needs alert routing config UI

  • integrations → parent module the Integrations page hangs off; also gates the pull-model code path (GitHub, AWS, GCP API polling) used when collectors aren't deployed

  • integrations.notifications → Slack/Teams/Email channel registration — every org needs at least one alert channel

  • groups → RBAC team scoping for any non-trivial permission grant

  • api_keys → programmatic access (CI/CD pipelines, scripts, out-of-band agent registration)

Auto-included by ResolvePresetModules so individual presets don't have to enumerate them. Adding a module here = retroactive opt-in for every tenant on next preset apply.

View Source
var ModuleDependencies = map[string][]Dependency{

	"attack_surface": {
		{ModuleID: "assets", Type: DependencyHard, Reason: "attack surface is computed from assets"},
	},
	"scope_config": {
		{ModuleID: "assets", Type: DependencyHard, Reason: "scope rules select assets"},
	},
	"business_services": {
		{ModuleID: "assets", Type: DependencyHard, Reason: "services map to underlying assets"},
	},
	"ctem_cycles": {
		{ModuleID: "scope_config", Type: DependencyHard, Reason: "cycles operate on a defined scope"},
		{ModuleID: "findings", Type: DependencySoft, Reason: "cycle phases reference findings progress"},
	},
	"relationships": {
		{ModuleID: "assets", Type: DependencyHard, Reason: "relationships are between assets"},
	},

	"credentials": {
		{ModuleID: "assets", Type: DependencyHard, Reason: "leaked credentials are scoped to assets"},
	},
	"components": {
		{ModuleID: "assets", Type: DependencyHard, Reason: "components belong to assets (repos, images, runtimes)"},
	},
	"branches": {
		{ModuleID: "assets", Type: DependencyHard, Reason: "branches belong to repository assets"},
		{ModuleID: "components", Type: DependencySoft, Reason: "branch views surface component inventories per branch"},
	},
	"vulnerabilities": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "vulnerability views list findings of type=vulnerability"},
	},

	"threat_intel": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "threat intel enriches findings"},
	},
	"exposures": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "an exposure is a finding in a specific lifecycle state"},
	},
	"ai_triage": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "triage operates on findings"},
		{ModuleID: "threat_intel", Type: DependencySoft, Reason: "triage uses KEV/EPSS context when scoring"},
	},
	"priority_rules": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "rules classify findings"},
		{ModuleID: "threat_intel", Type: DependencySoft, Reason: "rule conditions often reference KEV/EPSS"},
	},
	"risk_analysis": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "risk scoring reads finding severity + exposure"},
		{ModuleID: "assets", Type: DependencyHard, Reason: "per-asset risk requires the asset inventory"},
	},
	"business_impact": {
		{ModuleID: "business_services", Type: DependencyHard, Reason: "impact scoring is weighted by business-service mapping"},
		{ModuleID: "findings", Type: DependencyHard, Reason: "impact is computed from finding severity × service weight"},
	},
	"risk_scoring": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "risk scoring operates on findings"},
	},

	"pentest": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "pentest campaigns produce findings"},
	},
	"attack_simulation": {
		{ModuleID: "attacker_profiles", Type: DependencyHard, Reason: "simulation requires an attacker profile to emulate"},
		{ModuleID: "assets", Type: DependencyHard, Reason: "simulation needs target assets"},
	},
	"control_testing": {
		{ModuleID: "compensating_controls", Type: DependencyHard, Reason: "control testing validates compensating controls"},
	},
	"compensating_controls": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "compensating controls reduce severity of findings"},
	},

	"remediation": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "remediation closes findings"},
	},
	"remediation_tasks": {
		{ModuleID: "remediation", Type: DependencyHard, Reason: "tasks are the operator-facing queue of the remediation engine"},
	},
	"workflows": {

		{ModuleID: "findings", Type: DependencySoft, Reason: "finding-lifecycle triggers are a subset of workflow triggers"},
		{ModuleID: "integrations", Type: DependencySoft, Reason: "most workflow actions route through integrations (Jira, Slack)"},
	},
	"suppressions": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "suppressions suppress findings"},
	},
	"sla": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "SLA tracks time-to-remediate per finding"},
	},
	"policies": {
		{ModuleID: "findings", Type: DependencySoft, Reason: "most policy checks classify findings"},
	},
	"compliance": {
		{ModuleID: "findings", Type: DependencySoft, Reason: "compliance reports aggregate findings against frameworks"},
	},
	"iocs": {
		{ModuleID: "threat_intel", Type: DependencySoft, Reason: "IOC enrichment pulls from threat intel feeds"},
	},
	"scan_profiles": {
		{ModuleID: "scans", Type: DependencyHard, Reason: "profiles are parameterised scan configurations"},
	},

	"reports": {
		{ModuleID: "findings", Type: DependencySoft, Reason: "most report types render finding data"},
	},
	"executive_summary": {
		{ModuleID: "findings", Type: DependencyHard, Reason: "exec summary rolls up finding metrics"},
		{ModuleID: "scans", Type: DependencySoft, Reason: "scan coverage metrics appear on the summary"},
	},
	"ctem_maturity": {
		{ModuleID: "ctem_cycles", Type: DependencyHard, Reason: "maturity is computed across CTEM cycles"},
		{ModuleID: "findings", Type: DependencySoft, Reason: "F3/B4 invariants rely on finding SLA data"},
	},
	"mitre_coverage": {
		{ModuleID: "threat_intel", Type: DependencyHard, Reason: "coverage maps detections to MITRE techniques"},
		{ModuleID: "compensating_controls", Type: DependencySoft, Reason: "control coverage appears on the heatmap"},
	},
	"sbom_export": {
		{ModuleID: "components", Type: DependencyHard, Reason: "SBOM is generated from the component inventory"},
	},

	"scanner_templates": {
		{ModuleID: "scans", Type: DependencyHard, Reason: "templates are consumed by scans"},
	},
	"template_sources": {
		{ModuleID: "scanner_templates", Type: DependencyHard, Reason: "sources feed the template catalogue"},
	},
	"scan_pipelines": {
		{ModuleID: "scans", Type: DependencyHard, Reason: "pipelines orchestrate scan runs"},
		{ModuleID: "scanner_templates", Type: DependencySoft, Reason: "pipelines typically invoke templates"},
	},
}

ModuleDependencies is the platform-wide dependency graph, keyed by the dependent module ID. Core modules (dashboard, assets, findings, scans, team, roles, audit, settings) are never listed as keys here because the core-module check short-circuits ValidateToggle before dependency logic runs — they are structurally un-disable-able.

When adding a new feature, add its entry here. When removing, delete the entry AND search for references in values. The unit test TestReferencedModulesExist enforces both sides.

View Source
var ModulePermissionMapping = map[string]string{

	ModuleDashboard: "dashboard:read",
	ModuleAssets:    "assets:read",
	ModuleFindings:  "findings:read",
	ModuleScans:     "scans:read",

	ModuleCredentials:     "findings:credentials:read",
	ModuleComponents:      "assets:components:read",
	ModuleBranches:        "assets:read",
	ModuleVulnerabilities: "findings:vulnerabilities:read",

	ModuleThreatIntel: "threat_intel:read",
	ModuleExposures:   "findings:exposures:read",
	ModuleAITriage:    "ai_triage:read",
	ModuleSLA:         "settings:sla:read",

	ModulePentest: "pentest:campaigns:read",

	ModuleCompliance: "compliance:frameworks:read",

	ModuleRemediation:  "findings:remediation:read",
	ModuleSuppressions: "findings:suppressions:read",
	ModulePolicies:     "findings:policies:read",

	ModuleReports: "reports:read",
	ModuleAudit:   "audit:read",

	ModuleIntegrations:         "integrations:read",
	ModuleAgents:               "agents:read",
	ModuleTeam:                 "team:read",
	ModuleGroups:               "team:groups:read",
	ModuleRoles:                "team:roles:read",
	ModuleSettings:             "settings:read",
	ModuleAPIKeys:              "integrations:api_keys:read",
	ModuleWebhooks:             "integrations:webhooks:read",
	ModuleNotificationSettings: "integrations:notifications:read",

	ModuleSources: "scans:sources:read",
	ModuleSecrets: "scans:secret_store:read",
	ModuleScope:   "attack_surface:scope:read",

	ModulePipelines:    "integrations:pipelines:read",
	ModuleTools:        "scans:tools:read",
	ModuleScanProfiles: "scans:profiles:read",
	ModuleIOCs:         "threat_intel:read",

	ModuleAttackSurface:    "attack_surface:read",
	ModuleScopeConfig:      "attack_surface:scope:read",
	ModuleBusinessServices: "attack_surface:business_services:read",
	ModuleCTEMCycles:       "attack_surface:cycles:read",
	ModuleAttackerProfiles: "threat_intel:read",
	ModuleRelationships:    "assets:read",

	ModulePriorityRules:  "findings:read",
	ModuleRiskAnalysis:   "findings:read",
	ModuleBusinessImpact: "attack_surface:business_services:read",
	ModuleRiskScoring:    "settings:read",

	ModuleCompensatingControls: "findings:compensating_controls:read",

	ModuleWorkflows:        "findings:workflows:read",
	ModuleRemediationTasks: "findings:remediation:read",

	ModuleCTEMMaturity:     "dashboard:read",
	ModuleExecutiveSummary: "reports:read",
	ModuleMITRECoverage:    "threat_intel:read",
	ModuleSBOMExport:       "assets:components:read",

	ModuleScannerTemplates: "scans:templates:read",
	ModuleTemplateSources:  "scans:templates:read",
	ModuleScanPipelines:    "scans:pipelines:read",
}

ModulePermissionMapping maps module IDs to their required read permissions. This is used to filter modules based on user's RBAC permissions. A user must have at least the read permission to see the module in sidebar. These permissions MUST match the permission IDs seeded in 000005_permissions.up.sql

View Source
var ModulePresets = []ModulePreset{
	presetMinimal,
	presetAssetInventory,
	presetVMEssentials,
	presetASM,
	presetOffensive,
	presetSBOM,
	presetCSPM,
	presetCompliance,
	presetCTEMFull,
}

ModulePresets is the static catalogue of bundles shown on the Settings → Modules preset picker and during tenant onboarding. Order matters — presented to users in this order in the UI.

UserFacingModuleIDs defines modules shown on the Module Management page. Only modules that directly map to sidebar navigation sections are included. Modules like agents, tools, pipelines are bundled under "scans" in sidebar, so toggling them individually has no sidebar effect — they are excluded.

Functions

func BuildSubModuleID

func BuildSubModuleID(parentModuleID, subModuleName string) string

BuildSubModuleID constructs a sub-module ID from parent and child. Example: BuildSubModuleID("integrations", "scm") returns "integrations.scm"

func BuildSubModuleSlug

func BuildSubModuleSlug(parentModuleID, subModuleName string) string

BuildSubModuleSlug constructs a sub-module slug from parent and child. Example: BuildSubModuleSlug("integrations", "scm") returns "integrations-scm"

func CanDisable added in v0.2.0

func CanDisable(moduleID string, enabledModules map[string]bool) (blockers []ToggleBlocker, warnings []ToggleWarning)

CanDisable checks whether moduleID can be disabled given the set of currently-enabled modules. The function walks ModuleDependencies backwards: for every module that depends on moduleID, if that dependent is enabled, the edge type decides blocker vs warning.

Implicit sub-module cascade: every sub-module "<parent>.<sub>" is treated as hard-depending on its parent. Disabling `assets` therefore auto-blocks on every enabled `assets.*` sub-module without needing explicit edges per sub-module in ModuleDependencies. The inverse direction (disabling a sub-module) does NOT cascade — sub-modules are leaf toggles.

enabledModules MUST already reflect the *current* tenant state (before the toggle). A module listed in enabledModules with value false is treated as disabled.

Returns two disjoint slices: blockers (hard) and warnings (soft). Empty blockers = toggle is allowed.

func DetectCycle added in v0.2.0

func DetectCycle() []string

DetectCycle returns the first cycle found in the hard-edge subgraph, or nil if acyclic. Cycle is returned as a slice of module IDs in traversal order — the last element repeats the first. Used by the CI unit test to guarantee the spec is sane; a cycle here would mean "A requires B, B requires A" which is a product-design bug.

func FilterModuleIDsByPermissions

func FilterModuleIDsByPermissions(moduleIDs []string, userPermissions []string, isAdmin bool) []string

FilterModuleIDsByPermissions filters module IDs based on user's permissions.

func GetCategoryDisplayName

func GetCategoryDisplayName(category string) string

GetCategoryDisplayName returns the display name for a category.

func GetDefaultEventTypeIDs

func GetDefaultEventTypeIDs(eventTypes []*EventType) []string

GetDefaultEventTypeIDs returns the IDs of event types that are default enabled.

func GetRequiredPermission

func GetRequiredPermission(moduleID string) string

GetRequiredPermission returns the required permission for a module. Returns empty string if the module has no permission requirement.

func IsCoreModule added in v0.1.2

func IsCoreModule(moduleID string) bool

IsCoreModule returns true if the module is essential for platform operation.

func IsUserFacing added in v0.1.2

func IsUserFacing(moduleID string) bool

IsUserFacing returns true if the module should be shown in the admin Module Management page. Internal modules are hidden.

func ResolvePresetModules added in v0.2.0

func ResolvePresetModules(p *ModulePreset) map[string]bool

ResolvePresetModules returns the full set of module IDs a preset enables, including:

  • every module in EnabledModules
  • every core module (auto-on)
  • every hard transitive dep of the above (auto-on to satisfy graph)

The returned set is what should be written to tenant_modules when the preset is applied. Modules not in the set are treated as disabled.

func TransitiveDependencies added in v0.2.0

func TransitiveDependencies(moduleID string) []string

TransitiveDependencies walks hard edges recursively from moduleID and returns every module moduleID ultimately needs. The result excludes moduleID itself. Stable order for reproducible output. Soft edges are intentionally skipped — they describe degradation, not requirement.

func ValidateSubModuleID

func ValidateSubModuleID(fullSubModuleID string) error

ValidateSubModuleID validates that a sub-module ID follows the correct format. Returns error if the ID is malformed (e.g., double separator, empty parts).

Types

type Dependency added in v0.2.0

type Dependency struct {
	ModuleID string
	Type     DependencyType
	Reason   string
}

Dependency is one edge: "moduleID of the containing map key requires ModuleID".

func RequiredToEnable added in v0.2.0

func RequiredToEnable(moduleID string, enabledModules map[string]bool) []Dependency

RequiredToEnable returns the hard dependencies of moduleID that are currently NOT enabled. The caller must enable these first (or enable moduleID + its missing hard deps atomically).

type DependencyType added in v0.2.0

type DependencyType string

DependencyType classifies an edge in the module dependency graph.

const (
	// DependencyHard means the dependent module cannot function without the target.
	DependencyHard DependencyType = "hard"
	// DependencySoft means the dependent module works but has degraded features.
	DependencySoft DependencyType = "soft"
)

type EventType

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

EventType represents a notification event type stored in the database. This is the single source of truth for all event types in the system.

func ReconstructEventType

func ReconstructEventType(
	id, slug, name, description, category, icon, color string,
	severityApplicable, isDefault, isActive bool,
	displayOrder int,
) *EventType

ReconstructEventType creates an EventType from stored data.

func (*EventType) Category

func (e *EventType) Category() string

func (*EventType) Color

func (e *EventType) Color() string

func (*EventType) Description

func (e *EventType) Description() string

func (*EventType) DisplayOrder

func (e *EventType) DisplayOrder() int

func (*EventType) ID

func (e *EventType) ID() string

func (*EventType) Icon

func (e *EventType) Icon() string

func (*EventType) IsActive

func (e *EventType) IsActive() bool

func (*EventType) IsDefault

func (e *EventType) IsDefault() bool

func (*EventType) Name

func (e *EventType) Name() string

func (*EventType) SeverityApplicable

func (e *EventType) SeverityApplicable() bool

func (*EventType) Slug

func (e *EventType) Slug() string

type EventTypeCategory

type EventTypeCategory struct {
	ID         string       `json:"id"`
	Name       string       `json:"name"`
	EventTypes []*EventType `json:"event_types"`
}

EventTypeCategory represents a category of event types for UI grouping.

func GroupEventTypesByCategory

func GroupEventTypesByCategory(eventTypes []*EventType) []EventTypeCategory

GroupEventTypesByCategory groups event types by their category.

type EventTypeWithModule

type EventTypeWithModule struct {
	*EventType
	ModuleID string
}

EventTypeWithModule represents an event type with its associated module ID.

type Module

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

Module represents a feature module in the system.

func FilterModulesByPermissions

func FilterModulesByPermissions(modules []*Module, userPermissions []string, isAdmin bool) []*Module

FilterModulesByPermissions filters modules based on user's permissions. Returns only modules that the user has at least read permission for. Admin/Owner users should pass isAdmin=true to bypass permission checks.

func ReconstructModule

func ReconstructModule(
	id, slug, name, description, icon, category string,
	displayOrder int,
	isActive bool,
	isCore bool,
	releaseStatus string,
	parentModuleID *string,
	eventTypes []string,
) *Module

ReconstructModule creates a Module from stored data.

func (*Module) Category

func (m *Module) Category() string

func (*Module) Description

func (m *Module) Description() string

func (*Module) DisplayOrder

func (m *Module) DisplayOrder() int

func (*Module) EventTypes

func (m *Module) EventTypes() []string

func (*Module) HasParent

func (m *Module) HasParent(parentID string) bool

HasParent returns true if this module's parent is the given ID.

func (*Module) ID

func (m *Module) ID() string

func (*Module) Icon

func (m *Module) Icon() string

func (*Module) IsActive

func (m *Module) IsActive() bool

func (*Module) IsBeta

func (m *Module) IsBeta() bool

IsBeta returns true if the module is in beta testing.

func (*Module) IsComingSoon

func (m *Module) IsComingSoon() bool

IsComingSoon returns true if the module is not released yet.

func (*Module) IsCore added in v0.1.2

func (m *Module) IsCore() bool

func (*Module) IsDeprecated

func (m *Module) IsDeprecated() bool

IsDeprecated returns true if the module is being phased out.

func (*Module) IsReleased

func (m *Module) IsReleased() bool

IsReleased returns true if the module is generally available.

func (*Module) IsSubModule

func (m *Module) IsSubModule() bool

IsSubModule returns true if this module has a parent module.

func (*Module) Name

func (m *Module) Name() string

func (*Module) ParentModuleID

func (m *Module) ParentModuleID() *string

func (*Module) ReleaseStatus

func (m *Module) ReleaseStatus() ReleaseStatus

func (*Module) Slug

func (m *Module) Slug() string

type ModulePreset added in v0.2.0

type ModulePreset struct {
	// ID — stable identifier, used by the apply endpoint. kebab-case.
	ID string
	// Name — display label shown to admins.
	Name string
	// Description — one-sentence summary of the bundle's purpose.
	Description string
	// TargetPersona — who this preset is designed for.
	TargetPersona string
	// KeyOutcomes — 3-5 bullets the admin can expect after applying.
	KeyOutcomes []string
	// EnabledModules — explicit allow-list. Core modules may be
	// omitted; they get implicitly included. Hard deps must all be
	// present — enforced by TestPresetsSatisfyHardDeps at CI.
	EnabledModules []string
	// Icon — lucide icon name for the preset card.
	Icon string
	// RecommendedFor — audience tags (e.g. "SMB", "mid-market",
	// "security analyst"). Used in marketing copy on the picker.
	RecommendedFor []string
}

ModulePreset defines a curated bundle of enabled modules for a specific use case (e.g. "VM Essentials" for SMB vulnerability teams).

func FindPreset added in v0.2.0

func FindPreset(id string) *ModulePreset

FindPreset returns the preset with the given ID, or nil when not found.

type ModuleRepository

type ModuleRepository interface {
	// GetByID retrieves a module by its ID.
	GetByID(ctx context.Context, id string) (*Module, error)

	// GetBySlug retrieves a module by its slug.
	GetBySlug(ctx context.Context, slug string) (*Module, error)

	// ListAll returns all modules.
	ListAll(ctx context.Context) ([]*Module, error)

	// ListActive returns all active modules.
	ListActive(ctx context.Context) ([]*Module, error)

	// ListByCategory returns modules filtered by category.
	ListByCategory(ctx context.Context, category string) ([]*Module, error)
}

ModuleRepository defines the interface for module persistence operations.

type ReleaseStatus

type ReleaseStatus string

ReleaseStatus represents the product lifecycle status of a module.

const (
	// ReleaseStatusReleased means the module is generally available.
	ReleaseStatusReleased ReleaseStatus = "released"
	// ReleaseStatusComingSoon means the module is not released yet, shown as preview.
	ReleaseStatusComingSoon ReleaseStatus = "coming_soon"
	// ReleaseStatusBeta means the module is in beta testing.
	ReleaseStatusBeta ReleaseStatus = "beta"
	// ReleaseStatusDeprecated means the module is being phased out.
	ReleaseStatusDeprecated ReleaseStatus = "deprecated"
)

type TenantModuleOverride added in v0.1.2

type TenantModuleOverride struct {
	TenantID   shared.ID
	ModuleID   string
	IsEnabled  bool
	EnabledAt  *time.Time
	DisabledAt *time.Time
	UpdatedBy  *shared.ID
	UpdatedAt  time.Time
}

TenantModuleOverride represents a tenant's override for a module's enabled state.

type TenantModuleRepository added in v0.1.2

type TenantModuleRepository interface {
	// ListByTenant returns all module overrides for a tenant.
	ListByTenant(ctx context.Context, tenantID shared.ID) ([]*TenantModuleOverride, error)

	// UpsertBatch creates or updates multiple module overrides for a tenant.
	UpsertBatch(ctx context.Context, tenantID shared.ID, updates []TenantModuleUpdate, updatedBy *shared.ID) error

	// DeleteByTenant removes all module overrides for a tenant (reset to defaults).
	DeleteByTenant(ctx context.Context, tenantID shared.ID) error
}

TenantModuleRepository defines the interface for per-tenant module configuration.

type TenantModuleUpdate added in v0.1.2

type TenantModuleUpdate struct {
	ModuleID  string
	IsEnabled bool
}

TenantModuleUpdate represents a single module toggle request.

type ToggleBlocker added in v0.2.0

type ToggleBlocker struct {
	// BlockedModuleID is the module the caller attempted to disable.
	BlockedModuleID string
	// DependentModuleID is the module that depends on BlockedModuleID
	// and is still enabled, hence blocks the toggle.
	DependentModuleID string
	// Reason is the human-readable sentence from the dependency spec.
	Reason string
}

ToggleBlocker describes a module that cannot be disabled because another still-enabled module hard-depends on it.

type ToggleWarning added in v0.2.0

type ToggleWarning struct {
	DisabledModuleID  string
	DependentModuleID string
	Reason            string
}

ToggleWarning describes soft degradation — the toggle goes through, but the dependent module will run with reduced functionality.

Jump to

Keyboard shortcuts

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