Documentation
¶
Index ¶
- Variables
- type AddCommentInput
- type AddStatusChangeCommentInput
- type ApproveStatusInput
- type AutoAssignToOwnersResult
- type BulkAssignInput
- type BulkFixAppliedInput
- type BulkFixAppliedResult
- type BulkGuard
- type BulkGuardConfig
- type BulkUpdateResult
- type BulkUpdateStatusInput
- type BurpIssue
- type BurpIssues
- type CachedCategory
- type CachedFindingSource
- type CachedFindingSources
- type CancelApprovalInput
- type ClassifyFindingInput
- type CompensatingControlLookup
- type CreateFindingInput
- type CreateVulnerabilityInput
- type EPSSData
- type EPSSRepository
- type FindingActionsService
- func (s *FindingActionsService) AutoAssignToOwners(ctx context.Context, tenantID string, assignerID string, ...) (*AutoAssignToOwnersResult, error)
- func (s *FindingActionsService) BulkFixApplied(ctx context.Context, tenantID string, userID string, input BulkFixAppliedInput) (*BulkFixAppliedResult, error)
- func (s *FindingActionsService) BulkRejectByFilter(ctx context.Context, tenantID string, userID string, input RejectByFilterInput) (int64, error)
- func (s *FindingActionsService) BulkRejectFix(ctx context.Context, tenantID string, userID string, findingIDs []string, ...) (*BulkUpdateResult, error)
- func (s *FindingActionsService) BulkVerify(ctx context.Context, tenantID string, userID string, findingIDs []string, ...) (*BulkUpdateResult, error)
- func (s *FindingActionsService) BulkVerifyByFilter(ctx context.Context, tenantID string, userID string, input VerifyByFilterInput) (int64, error)
- func (s *FindingActionsService) GetRelatedCVEs(ctx context.Context, tenantID string, cveID string, ...) ([]vulnerability.RelatedCVE, error)
- func (s *FindingActionsService) ListFindingGroups(ctx context.Context, tenantID string, groupBy string, ...) (pagination.Result[*vulnerability.FindingGroup], error)
- func (s *FindingActionsService) RequestVerificationScan(ctx context.Context, tenantID, userID string, ...) (*RequestVerificationScanResult, error)
- func (s *FindingActionsService) SetVerificationScanTrigger(trigger VerificationScanTrigger)
- type FindingCommentService
- func (s *FindingCommentService) AddComment(ctx context.Context, input AddCommentInput) (*vulnerability.FindingComment, error)
- func (s *FindingCommentService) AddStatusChangeComment(ctx context.Context, input AddStatusChangeCommentInput) (*vulnerability.FindingComment, error)
- func (s *FindingCommentService) CountFindingComments(ctx context.Context, findingID string) (int, error)
- func (s *FindingCommentService) DeleteComment(ctx context.Context, tenantID, commentID, authorID string) error
- func (s *FindingCommentService) GetComment(ctx context.Context, commentID string) (*vulnerability.FindingComment, error)
- func (s *FindingCommentService) ListFindingComments(ctx context.Context, findingID string) ([]*vulnerability.FindingComment, error)
- func (s *FindingCommentService) UpdateComment(ctx context.Context, tenantID, commentID, authorID string, ...) (*vulnerability.FindingComment, error)
- type FindingImportService
- type FindingLifecycleScheduler
- type FindingLifecycleSchedulerConfig
- type FindingNotifier
- type FindingSourceCacheService
- func (s *FindingSourceCacheService) GetAll(ctx context.Context) (*CachedFindingSources, error)
- func (s *FindingSourceCacheService) GetByCategory(ctx context.Context, categoryCode string) ([]*CachedFindingSource, error)
- func (s *FindingSourceCacheService) GetByCode(ctx context.Context, code string) (*CachedFindingSource, error)
- func (s *FindingSourceCacheService) GetCategories(ctx context.Context) ([]*CachedCategory, error)
- func (s *FindingSourceCacheService) InvalidateAll(ctx context.Context) error
- func (s *FindingSourceCacheService) IsValidCode(ctx context.Context, code string) (bool, error)
- func (s *FindingSourceCacheService) Refresh(ctx context.Context) (*CachedFindingSources, error)
- func (s *FindingSourceCacheService) WarmCache(ctx context.Context) error
- type FindingSourceService
- func (s *FindingSourceService) GetCategory(ctx context.Context, categoryID string) (*findingsource.Category, error)
- func (s *FindingSourceService) GetCategoryByCode(ctx context.Context, code string) (*findingsource.Category, error)
- func (s *FindingSourceService) GetFindingSource(ctx context.Context, findingSourceID string) (*findingsource.FindingSource, error)
- func (s *FindingSourceService) GetFindingSourceByCode(ctx context.Context, code string) (*findingsource.FindingSource, error)
- func (s *FindingSourceService) IsValidSourceCode(ctx context.Context, code string) (bool, error)
- func (s *FindingSourceService) ListActiveCategories(ctx context.Context) ([]*findingsource.Category, error)
- func (s *FindingSourceService) ListActiveFindingSources(ctx context.Context) ([]*findingsource.FindingSource, error)
- func (s *FindingSourceService) ListActiveFindingSourcesByCategory(ctx context.Context, categoryID string) ([]*findingsource.FindingSource, error)
- func (s *FindingSourceService) ListActiveFindingSourcesWithCategory(ctx context.Context) ([]*findingsource.FindingSourceWithCategory, error)
- func (s *FindingSourceService) ListCategories(ctx context.Context, filter findingsource.CategoryFilter, ...) (pagination.Result[*findingsource.Category], error)
- func (s *FindingSourceService) ListFindingSources(ctx context.Context, filter findingsource.Filter, ...) (pagination.Result[*findingsource.FindingSource], error)
- func (s *FindingSourceService) ListFindingSourcesWithCategory(ctx context.Context, filter findingsource.Filter, ...) (pagination.Result[*findingsource.FindingSourceWithCategory], error)
- type GetFindingStatsInput
- type ImportResult
- type KEVData
- type KEVRepository
- type ListFindingsInput
- type ListVulnerabilitiesInput
- type PriorityAuditEntry
- type PriorityAuditRepository
- type PriorityChangeEvent
- type PriorityChangePublisher
- type PriorityClassificationService
- func (s *PriorityClassificationService) ClassifyFinding(ctx context.Context, tenantID shared.ID, finding *vulnerability.Finding, ...) error
- func (s *PriorityClassificationService) EnrichAndClassifyBatch(ctx context.Context, tenantID shared.ID, findings []*vulnerability.Finding, ...) error
- func (s *PriorityClassificationService) SetChangePublisher(p PriorityChangePublisher)
- func (s *PriorityClassificationService) SetControlLookup(lookup CompensatingControlLookup)
- func (s *PriorityClassificationService) SetPriorityFloodGuard(g *PriorityFloodGuard)
- type PriorityFloodConfig
- type PriorityFloodGuard
- type PriorityRuleRepository
- type RejectApprovalInput
- type RejectByFilterInput
- type RequestApprovalInput
- type RequestVerificationScanInput
- type RequestVerificationScanResult
- type TenantLister
- type UpdateCommentInput
- type UpdateFindingStatusInput
- type UpdateVulnerabilityInput
- type VerificationScanTrigger
- type VerifyByFilterInput
- type VulnerabilityService
- func (s *VulnerabilityService) AddFindingComment(ctx context.Context, tenantID, findingID, authorID, content string) (*vulnerability.FindingComment, error)
- func (s *VulnerabilityService) ApproveStatus(ctx context.Context, input ApproveStatusInput) (*vulnerability.Approval, error)
- func (s *VulnerabilityService) AssignFinding(ctx context.Context, findingID, tenantID, userID, assignerID string) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) BulkAssignFindings(ctx context.Context, tenantID string, input BulkAssignInput) (*BulkUpdateResult, error)
- func (s *VulnerabilityService) BulkUpdateFindingStatus(ctx context.Context, tenantID shared.ID, ids []shared.ID, ...) error
- func (s *VulnerabilityService) BulkUpdateFindingsStatus(ctx context.Context, tenantID string, input BulkUpdateStatusInput) (*BulkUpdateResult, error)
- func (s *VulnerabilityService) CancelApproval(ctx context.Context, input CancelApprovalInput) (*vulnerability.Approval, error)
- func (s *VulnerabilityService) ClassifyFinding(ctx context.Context, findingID, tenantID string, input ClassifyFindingInput) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) CountAssetFindings(ctx context.Context, tenantID string, assetID string) (int64, error)
- func (s *VulnerabilityService) CountOpenAssetFindings(ctx context.Context, tenantID string, assetID string) (int64, error)
- func (s *VulnerabilityService) CreateFinding(ctx context.Context, input CreateFindingInput) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) CreateVulnerability(ctx context.Context, input CreateVulnerabilityInput) (*vulnerability.Vulnerability, error)
- func (s *VulnerabilityService) DeleteAssetFindings(ctx context.Context, tenantID string, assetID string) error
- func (s *VulnerabilityService) DeleteFinding(ctx context.Context, findingID string, tenantID string) error
- func (s *VulnerabilityService) DeleteFindingComment(ctx context.Context, tenantID, commentID, authorID string) error
- func (s *VulnerabilityService) DeleteVulnerability(ctx context.Context, vulnID string) error
- func (s *VulnerabilityService) GetFinding(ctx context.Context, tenantID, findingID string) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) GetFindingCountsByScanID(ctx context.Context, tenantID, scanID string) (vulnerability.SeverityCounts, error)
- func (s *VulnerabilityService) GetFindingStats(ctx context.Context, tenantID string) (*vulnerability.FindingStats, error)
- func (s *VulnerabilityService) GetFindingStatsWithScope(ctx context.Context, input GetFindingStatsInput) (*vulnerability.FindingStats, error)
- func (s *VulnerabilityService) GetFindingWithScope(ctx context.Context, tenantID, findingID, actingUserID string, isAdmin bool) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) GetVulnerability(ctx context.Context, vulnID string) (*vulnerability.Vulnerability, error)
- func (s *VulnerabilityService) GetVulnerabilityByCVE(ctx context.Context, cveID string) (*vulnerability.Vulnerability, error)
- func (s *VulnerabilityService) ListAssetFindings(ctx context.Context, tenantID string, assetID string, sort string, ...) (pagination.Result[*vulnerability.Finding], error)
- func (s *VulnerabilityService) ListFindingApprovals(ctx context.Context, tenantID, findingID string) ([]*vulnerability.Approval, error)
- func (s *VulnerabilityService) ListFindingComments(ctx context.Context, findingID string) ([]*vulnerability.FindingComment, error)
- func (s *VulnerabilityService) ListFindings(ctx context.Context, input ListFindingsInput) (pagination.Result[*vulnerability.Finding], error)
- func (s *VulnerabilityService) ListPendingApprovals(ctx context.Context, tenantID string, page, perPage int) (pagination.Result[*vulnerability.Approval], error)
- func (s *VulnerabilityService) ListVulnerabilities(ctx context.Context, input ListVulnerabilitiesInput) (pagination.Result[*vulnerability.Vulnerability], error)
- func (s *VulnerabilityService) RejectApproval(ctx context.Context, input RejectApprovalInput) (*vulnerability.Approval, error)
- func (s *VulnerabilityService) RequestApproval(ctx context.Context, input RequestApprovalInput) (*vulnerability.Approval, error)
- func (s *VulnerabilityService) SetAITriageService(svc *aitriage.AITriageService)
- func (s *VulnerabilityService) SetAccessControlRepository(repo accesscontrol.Repository)
- func (s *VulnerabilityService) SetActivityService(svc *activity.FindingActivityService)
- func (s *VulnerabilityService) SetApprovalRepository(repo vulnerability.ApprovalRepository)
- func (s *VulnerabilityService) SetAssignmentEngine(engine *assignment.Engine)
- func (s *VulnerabilityService) SetCommentRepository(repo vulnerability.FindingCommentRepository)
- func (s *VulnerabilityService) SetDataFlowRepository(repo vulnerability.DataFlowRepository)
- func (s *VulnerabilityService) SetFindingNotifier(notifier FindingNotifier)
- func (s *VulnerabilityService) SetFindingTags(ctx context.Context, findingID, tenantID string, tags []string) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) SetOutboxService(db *sql.DB, svc *outbox.Service)
- func (s *VulnerabilityService) SetUserNotificationService(svc *integration.NotificationService)
- func (s *VulnerabilityService) SetUserRepository(repo user.Repository)
- func (s *VulnerabilityService) TriageFinding(ctx context.Context, findingID, tenantID, userID, reason string) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) UnassignFinding(ctx context.Context, findingID, tenantID, actorID string) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) UpdateFindingComment(ctx context.Context, tenantID, commentID, authorID, content string) (*vulnerability.FindingComment, error)
- func (s *VulnerabilityService) UpdateFindingSeverity(ctx context.Context, findingID, tenantID, severityStr, actorID string) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) UpdateFindingStatus(ctx context.Context, findingID string, tenantID string, ...) (*vulnerability.Finding, error)
- func (s *VulnerabilityService) UpdateVulnerability(ctx context.Context, vulnID string, input UpdateVulnerabilityInput) (*vulnerability.Vulnerability, error)
- func (s *VulnerabilityService) VerifyFinding(ctx context.Context, findingID, tenantID, userID string) (*vulnerability.Finding, error)
Constants ¶
This section is empty.
Variables ¶
var ErrBulkBudgetExceeded = errors.New("bulk operation budget exceeded for this hour")
ErrBulkBudgetExceeded is returned when the rolling-hour budget is exhausted for the tenant.
var ErrBulkNegativeSize = errors.New("bulk request size must be positive")
ErrBulkNegativeSize defends against callers passing a computed size that went negative (overflow bugs, bad filters).
var ErrBulkTooLarge = errors.New("bulk request exceeds size ceiling; requires operator approval")
ErrBulkTooLarge is returned when a single request exceeds the per-request ceiling without operator approval.
var ErrPriorityFloodSuppressed = errors.New("tenant priority flood budget exceeded; downstream fan-out suppressed")
ErrPriorityFloodSuppressed is returned by ShouldFanOut when the tenant has already consumed its rolling budget. Classification is NOT reverted; only downstream side effects are skipped.
Functions ¶
This section is empty.
Types ¶
type AddCommentInput ¶
type AddCommentInput struct {
TenantID string `validate:"required,uuid"`
FindingID string `validate:"required,uuid"`
AuthorID string `validate:"required,uuid"`
Content string `validate:"required,min=1,max=10000"`
}
AddCommentInput represents the input for adding a comment.
type AddStatusChangeCommentInput ¶
type AddStatusChangeCommentInput struct {
TenantID string `validate:"required,uuid"`
FindingID string `validate:"required,uuid"`
AuthorID string `validate:"required,uuid"`
Content string `validate:"max=10000"`
OldStatus string `validate:"required,finding_status"`
NewStatus string `validate:"required,finding_status"`
}
AddStatusChangeCommentInput represents the input for adding a status change comment.
type ApproveStatusInput ¶
type ApproveStatusInput struct {
TenantID string `json:"tenant_id" validate:"required,uuid"`
ApprovalID string `json:"approval_id" validate:"required,uuid"`
ApprovedBy string `json:"approved_by" validate:"required,uuid"`
}
ApproveStatusInput represents the input for approving a status change.
type AutoAssignToOwnersResult ¶
type AutoAssignToOwnersResult struct {
Assigned int `json:"assigned"`
ByOwner map[string]int `json:"by_owner"`
Unassigned int `json:"unassigned"`
}
AutoAssignToOwnersResult is the result of auto-assign operation.
type BulkAssignInput ¶
BulkAssignInput represents input for bulk assignment.
type BulkFixAppliedInput ¶
type BulkFixAppliedInput struct {
Filter vulnerability.FindingFilter
IncludeRelatedCVEs bool
Note string // REQUIRED
Reference string // optional (commit hash, patch ID)
}
BulkFixAppliedInput is the input for bulk fix-applied operation.
type BulkFixAppliedResult ¶
type BulkFixAppliedResult struct {
Updated int `json:"updated"`
Skipped int `json:"skipped"`
ByCVE map[string]int `json:"by_cve,omitempty"`
AssetsAffected int `json:"assets_affected"`
}
BulkFixAppliedResult is the result of bulk fix-applied operation.
type BulkGuard ¶
type BulkGuard struct {
// contains filtered or unexported fields
}
BulkGuard is the single service used by all bulk handlers before executing. Usage:
if err := guard.CheckBulk(tenantID, len(findingIDs), operatorApproved); err != nil {
return apierror.BadRequest(err.Error()).WriteJSON(w)
}
func NewBulkGuard ¶
func NewBulkGuard(cfg BulkGuardConfig) *BulkGuard
NewBulkGuard constructs a guard with defaults applied.
func (*BulkGuard) CheckBulk ¶
func (g *BulkGuard) CheckBulk(ctx context.Context, tenantID shared.ID, size int, operatorApproved bool) error
CheckBulk enforces both guards for a single request. On success, records the usage so subsequent calls see it. On rejection, usage is NOT recorded (the operation didn't happen).
The operator-approved flag bypasses SizeCeiling but NOT the hourly budget — even an approved operator cannot blast the tenant.
type BulkGuardConfig ¶
type BulkGuardConfig struct {
// SizeCeiling is the max number of rows a single bulk request
// can touch without operator approval. Default 500.
SizeCeiling int
// HourlyBudget is the max rows per tenant per hour. Default 10_000.
HourlyBudget int
// Now is injectable for deterministic tests.
Now func() time.Time
}
BulkGuardConfig tunes the two thresholds. Zero values take the documented defaults.
type BulkUpdateResult ¶
BulkUpdateResult represents the result of a bulk operation.
type BulkUpdateStatusInput ¶
type BulkUpdateStatusInput struct {
FindingIDs []string
Status string
Resolution string
ActorID string // User performing the bulk update
}
BulkUpdateStatusInput represents input for bulk status update.
type BurpIssue ¶
type BurpIssue struct {
XMLName xml.Name `xml:"issue"`
SerialNumber string `xml:"serialNumber"`
Type string `xml:"type"`
Name string `xml:"name"`
Host string `xml:"host"`
Path string `xml:"path"`
Location string `xml:"location"`
Severity string `xml:"severity"`
Confidence string `xml:"confidence"`
IssueBackground string `xml:"issueBackground"`
RemediationBG string `xml:"remediationBackground"`
IssueDetail string `xml:"issueDetail"`
RemediationDetail string `xml:"remediationDetail"`
RequestResponse []struct {
Request string `xml:"request"`
Response string `xml:"response"`
} `xml:"requestresponse"`
}
BurpIssue represents a single issue in Burp Suite XML export.
type BurpIssues ¶
BurpIssues is the root XML element.
type CachedCategory ¶
type CachedCategory struct {
ID string `json:"id"`
Code string `json:"code"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`
DisplayOrder int `json:"display_order"`
}
CachedCategory represents a category in the cache.
type CachedFindingSource ¶
type CachedFindingSource struct {
ID string `json:"id"`
Code string `json:"code"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
CategoryID string `json:"category_id,omitempty"`
CategoryCode string `json:"category_code,omitempty"`
CategoryName string `json:"category_name,omitempty"`
Icon string `json:"icon,omitempty"`
Color string `json:"color,omitempty"`
DisplayOrder int `json:"display_order"`
IsSystem bool `json:"is_system"`
}
CachedFindingSource represents a finding source in the cache.
type CachedFindingSources ¶
type CachedFindingSources struct {
Sources []*CachedFindingSource `json:"sources"`
Categories []*CachedCategory `json:"categories"`
ByCode map[string]int `json:"by_code"` // code -> index in Sources for O(1) lookup
ByCategory map[string][]int `json:"by_category"` // category_code -> indices in Sources
CachedAt time.Time `json:"cached_at"`
}
CachedFindingSources represents the cached finding source data.
type CancelApprovalInput ¶
type CancelApprovalInput struct {
TenantID string `json:"tenant_id" validate:"required,uuid"`
ApprovalID string `json:"approval_id" validate:"required,uuid"`
CanceledBy string `json:"canceled_by" validate:"required,uuid"`
}
CancelApprovalInput represents the input for cancelling a status change request.
type ClassifyFindingInput ¶
type ClassifyFindingInput struct {
CVEID string
CVSSScore *float64
CVSSVector string
CWEIDs []string
OWASPIDs []string
}
ClassifyFindingInput represents input for classification.
type CompensatingControlLookup ¶
type CompensatingControlLookup interface {
// GetEffectiveForAssets returns max reduction_factor per asset with active+effective controls.
// Returns map[assetID]reductionFactor (0.0-1.0).
GetEffectiveForAssets(ctx context.Context, tenantID shared.ID, assetIDs []shared.ID) (map[shared.ID]float64, error)
}
CompensatingControlLookup provides lookups for effective controls on assets/findings.
type CreateFindingInput ¶
type CreateFindingInput struct {
TenantID string `validate:"required,uuid"`
AssetID string `validate:"required,uuid"`
BranchID string `validate:"omitempty,uuid"`
VulnerabilityID string `validate:"omitempty,uuid"`
ComponentID string `validate:"omitempty,uuid"`
Source string `validate:"required,finding_source"`
ToolName string `validate:"required,max=100"`
ToolVersion string `validate:"max=50"`
RuleID string `validate:"max=255"`
FilePath string `validate:"max=500"`
StartLine int `validate:"min=0"`
EndLine int `validate:"min=0"`
StartColumn int `validate:"min=0"`
EndColumn int `validate:"min=0"`
Snippet string `validate:"max=5000"`
Message string `validate:"required,max=2000"`
Severity string `validate:"required,severity"`
ScanID string `validate:"max=100"`
}
CreateFindingInput represents the input for creating a finding.
type CreateVulnerabilityInput ¶
type CreateVulnerabilityInput struct {
CVEID string `validate:"required,cve_id"`
Title string `validate:"required,min=1,max=500"`
Description string `validate:"max=10000"`
Severity string `validate:"required,severity"`
CVSSScore *float64 `validate:"omitempty,min=0,max=10"`
CVSSVector string `validate:"max=100"`
EPSSScore *float64 `validate:"omitempty,min=0,max=1"`
EPSSPercentile *float64 `validate:"omitempty,min=0,max=1"`
ExploitAvailable bool
ExploitMaturity string `validate:"omitempty,exploit_maturity"`
FixedVersions []string `validate:"max=50,dive,max=100"`
Remediation string `validate:"max=5000"`
}
CreateVulnerabilityInput represents the input for creating a vulnerability.
type EPSSRepository ¶
type EPSSRepository interface {
GetByCVEIDs(ctx context.Context, cveIDs []string) (map[string]EPSSData, error)
}
EPSSRepository provides EPSS score lookups.
type FindingActionsService ¶
type FindingActionsService struct {
// contains filtered or unexported fields
}
FindingActionsService handles the closed-loop finding lifecycle: in_progress → fix_applied → resolved (verified by scan or security).
func NewFindingActionsService ¶
func NewFindingActionsService( findingRepo vulnerability.FindingRepository, accessCtrlRepo accesscontrol.Repository, groupRepo group.Repository, assetRepo asset.Repository, activityService *activity.FindingActivityService, db *sql.DB, logger *logger.Logger, ) *FindingActionsService
NewFindingActionsService creates a new FindingActionsService.
func (*FindingActionsService) AutoAssignToOwners ¶
func (s *FindingActionsService) AutoAssignToOwners( ctx context.Context, tenantID string, assignerID string, filter vulnerability.FindingFilter, ) (*AutoAssignToOwnersResult, error)
AutoAssignToOwners assigns findings to their asset owners. Only assigns findings that don't already have an assignee.
func (*FindingActionsService) BulkFixApplied ¶
func (s *FindingActionsService) BulkFixApplied( ctx context.Context, tenantID string, userID string, input BulkFixAppliedInput, ) (*BulkFixAppliedResult, error)
BulkFixApplied marks findings as fix_applied. Authorization: user must be assignee, group member, or asset owner for each finding.
func (*FindingActionsService) BulkRejectByFilter ¶
func (s *FindingActionsService) BulkRejectByFilter( ctx context.Context, tenantID string, userID string, input RejectByFilterInput, ) (int64, error)
BulkRejectByFilter reopens all fix_applied findings matching a filter.
func (*FindingActionsService) BulkRejectFix ¶
func (s *FindingActionsService) BulkRejectFix( ctx context.Context, tenantID string, userID string, findingIDs []string, reason string, ) (*BulkUpdateResult, error)
BulkRejectFix reopens fix_applied findings (fix was incorrect).
func (*FindingActionsService) BulkVerify ¶
func (s *FindingActionsService) BulkVerify( ctx context.Context, tenantID string, userID string, findingIDs []string, note string, ) (*BulkUpdateResult, error)
BulkVerify resolves fix_applied findings (manual security review).
func (*FindingActionsService) BulkVerifyByFilter ¶
func (s *FindingActionsService) BulkVerifyByFilter( ctx context.Context, tenantID string, userID string, input VerifyByFilterInput, ) (int64, error)
BulkVerifyByFilter resolves all fix_applied findings matching a filter. Used by Pending Review tab to approve entire groups at once.
func (*FindingActionsService) GetRelatedCVEs ¶
func (s *FindingActionsService) GetRelatedCVEs( ctx context.Context, tenantID string, cveID string, filter vulnerability.FindingFilter, ) ([]vulnerability.RelatedCVE, error)
GetRelatedCVEs finds CVEs that share the same component as the given CVE.
func (*FindingActionsService) ListFindingGroups ¶
func (s *FindingActionsService) ListFindingGroups( ctx context.Context, tenantID string, groupBy string, filter vulnerability.FindingFilter, page pagination.Pagination, ) (pagination.Result[*vulnerability.FindingGroup], error)
ListFindingGroups returns findings grouped by a dimension.
func (*FindingActionsService) RequestVerificationScan ¶
func (s *FindingActionsService) RequestVerificationScan( ctx context.Context, tenantID, userID string, input RequestVerificationScanInput, ) (*RequestVerificationScanResult, error)
RequestVerificationScan triggers a targeted quick scan on the asset associated with a finding. The finding must be in fix_applied status (dev has marked it as fixed; awaiting scan verification). The scan result is expected to either confirm the fix (→ resolved) or reveal the vuln still exists (→ back to in_progress) via the normal ingest pipeline.
func (*FindingActionsService) SetVerificationScanTrigger ¶
func (s *FindingActionsService) SetVerificationScanTrigger(trigger VerificationScanTrigger)
SetVerificationScanTrigger wires the scan trigger (called after both services are initialized).
type FindingCommentService ¶
type FindingCommentService struct {
// contains filtered or unexported fields
}
FindingCommentService handles finding comment operations.
func NewFindingCommentService ¶
func NewFindingCommentService( commentRepo vulnerability.FindingCommentRepository, findingRepo vulnerability.FindingRepository, log *logger.Logger, ) *FindingCommentService
NewFindingCommentService creates a new FindingCommentService.
func (*FindingCommentService) AddComment ¶
func (s *FindingCommentService) AddComment(ctx context.Context, input AddCommentInput) (*vulnerability.FindingComment, error)
AddComment adds a new comment to a finding.
func (*FindingCommentService) AddStatusChangeComment ¶
func (s *FindingCommentService) AddStatusChangeComment(ctx context.Context, input AddStatusChangeCommentInput) (*vulnerability.FindingComment, error)
AddStatusChangeComment adds a comment recording a status change.
func (*FindingCommentService) CountFindingComments ¶
func (s *FindingCommentService) CountFindingComments(ctx context.Context, findingID string) (int, error)
CountFindingComments counts comments for a finding.
func (*FindingCommentService) DeleteComment ¶
func (s *FindingCommentService) DeleteComment(ctx context.Context, tenantID, commentID, authorID string) error
DeleteComment deletes a comment. tenantID is required so the storage-layer WHERE clause rejects cross-tenant IDs (IDOR defense).
func (*FindingCommentService) GetComment ¶
func (s *FindingCommentService) GetComment(ctx context.Context, commentID string) (*vulnerability.FindingComment, error)
GetComment retrieves a comment by ID.
func (*FindingCommentService) ListFindingComments ¶
func (s *FindingCommentService) ListFindingComments(ctx context.Context, findingID string) ([]*vulnerability.FindingComment, error)
ListFindingComments retrieves all comments for a finding.
func (*FindingCommentService) UpdateComment ¶
func (s *FindingCommentService) UpdateComment(ctx context.Context, tenantID, commentID, authorID string, input UpdateCommentInput) (*vulnerability.FindingComment, error)
UpdateComment updates an existing comment. tenantID scopes the lookup — user in tenant A cannot resolve a comment id from tenant B even if they guess the UUID.
type FindingImportService ¶
type FindingImportService struct {
// contains filtered or unexported fields
}
FindingImportService handles importing findings from external scanner formats.
func NewFindingImportService ¶
func NewFindingImportService(repo vulnerability.FindingRepository, log *logger.Logger) *FindingImportService
NewFindingImportService creates a new import service.
func (*FindingImportService) ImportBurpXML ¶
func (s *FindingImportService) ImportBurpXML(ctx context.Context, tenantID, campaignID string, reader io.Reader) (*ImportResult, error)
ImportBurpXML parses Burp Suite XML and creates findings.
func (*FindingImportService) ImportCSV ¶
func (s *FindingImportService) ImportCSV(ctx context.Context, tenantID, campaignID string, reader io.Reader) (*ImportResult, error)
ImportCSV parses CSV with headers and creates findings. Expected headers: title, severity, description, affected_assets, steps_to_reproduce, poc_code, business_impact, remediation
type FindingLifecycleScheduler ¶
type FindingLifecycleScheduler struct {
// contains filtered or unexported fields
}
FindingLifecycleScheduler manages background tasks for finding lifecycle. This includes expiring findings on feature branches that have been inactive.
func NewFindingLifecycleScheduler ¶
func NewFindingLifecycleScheduler( findingRepo vulnerability.FindingRepository, tenantLister TenantLister, cfg FindingLifecycleSchedulerConfig, log *logger.Logger, ) *FindingLifecycleScheduler
NewFindingLifecycleScheduler creates a new scheduler.
func (*FindingLifecycleScheduler) Start ¶
func (s *FindingLifecycleScheduler) Start()
Start starts the scheduler.
func (*FindingLifecycleScheduler) Stop ¶
func (s *FindingLifecycleScheduler) Stop()
Stop stops the scheduler gracefully. Safe to call even if Start() was never called (e.g. when Enabled=false).
type FindingLifecycleSchedulerConfig ¶
type FindingLifecycleSchedulerConfig struct {
// CheckInterval is how often to run lifecycle tasks (default: 1 hour)
CheckInterval time.Duration
// DefaultExpiryDays is the default number of days after which
// feature branch findings are expired if not seen (default: 30)
// Individual branches can override this via retention_days setting.
DefaultExpiryDays int
// Enabled controls whether the scheduler runs (default: true)
Enabled bool
}
FindingLifecycleSchedulerConfig holds configuration for the scheduler.
func DefaultFindingLifecycleSchedulerConfig ¶
func DefaultFindingLifecycleSchedulerConfig() FindingLifecycleSchedulerConfig
DefaultFindingLifecycleSchedulerConfig returns default configuration.
type FindingNotifier ¶
type FindingNotifier interface {
// NotifyNewFinding sends a notification for a new finding.
// This should be called asynchronously to not block finding creation.
NotifyNewFinding(tenantID, title, body, severity, url string)
}
FindingNotifier is an interface for sending finding notifications asynchronously. Deprecated: Use outbox.Service with transactional outbox pattern instead.
type FindingSourceCacheService ¶
type FindingSourceCacheService struct {
// contains filtered or unexported fields
}
FindingSourceCacheService provides cached access to finding sources. Finding sources are system-level configuration that rarely changes, making them ideal candidates for aggressive caching.
Cache structure: - Key: "finding_sources:all" → CachedFindingSources (all sources with categories) - Key: "finding_sources:code:{code}" → single source (optional, for high-frequency lookups)
Cache invalidation: - Manual via InvalidateAll() when sources are modified (rare) - TTL-based expiration (24 hours)
This cache is GLOBAL (not per-tenant) because finding sources are system configuration.
func NewFindingSourceCacheService ¶
func NewFindingSourceCacheService( redisClient *redis.Client, repo findingsource.Repository, log *logger.Logger, ) (*FindingSourceCacheService, error)
NewFindingSourceCacheService creates a new finding source cache service.
func (*FindingSourceCacheService) GetAll ¶
func (s *FindingSourceCacheService) GetAll(ctx context.Context) (*CachedFindingSources, error)
GetAll returns all active finding sources with their categories (cached). This is the primary method for UI dropdowns and validation.
func (*FindingSourceCacheService) GetByCategory ¶
func (s *FindingSourceCacheService) GetByCategory(ctx context.Context, categoryCode string) ([]*CachedFindingSource, error)
GetByCategory returns finding sources filtered by category code (from cache).
func (*FindingSourceCacheService) GetByCode ¶
func (s *FindingSourceCacheService) GetByCode(ctx context.Context, code string) (*CachedFindingSource, error)
GetByCode returns a finding source by code (from cache). Returns nil if not found.
func (*FindingSourceCacheService) GetCategories ¶
func (s *FindingSourceCacheService) GetCategories(ctx context.Context) ([]*CachedCategory, error)
GetCategories returns all active categories (from cache).
func (*FindingSourceCacheService) InvalidateAll ¶
func (s *FindingSourceCacheService) InvalidateAll(ctx context.Context) error
InvalidateAll removes all cached finding source data. Call this when finding sources are modified (rare operation).
func (*FindingSourceCacheService) IsValidCode ¶
IsValidCode checks if a code is a valid active finding source (from cache).
func (*FindingSourceCacheService) Refresh ¶
func (s *FindingSourceCacheService) Refresh(ctx context.Context) (*CachedFindingSources, error)
Refresh forces a cache refresh by invalidating and reloading.
type FindingSourceService ¶
type FindingSourceService struct {
// contains filtered or unexported fields
}
FindingSourceService handles finding source-related business operations. Finding sources are read-only system configuration created via DB seed or by system admin.
func NewFindingSourceService ¶
func NewFindingSourceService(repo findingsource.Repository, categoryRepo findingsource.CategoryRepository, log *logger.Logger) *FindingSourceService
NewFindingSourceService creates a new FindingSourceService.
func (*FindingSourceService) GetCategory ¶
func (s *FindingSourceService) GetCategory(ctx context.Context, categoryID string) (*findingsource.Category, error)
GetCategory retrieves a category by ID.
func (*FindingSourceService) GetCategoryByCode ¶
func (s *FindingSourceService) GetCategoryByCode(ctx context.Context, code string) (*findingsource.Category, error)
GetCategoryByCode retrieves a category by code.
func (*FindingSourceService) GetFindingSource ¶
func (s *FindingSourceService) GetFindingSource(ctx context.Context, findingSourceID string) (*findingsource.FindingSource, error)
GetFindingSource retrieves a finding source by ID.
func (*FindingSourceService) GetFindingSourceByCode ¶
func (s *FindingSourceService) GetFindingSourceByCode(ctx context.Context, code string) (*findingsource.FindingSource, error)
GetFindingSourceByCode retrieves a finding source by code.
func (*FindingSourceService) IsValidSourceCode ¶
IsValidSourceCode checks if the code is a valid active finding source.
func (*FindingSourceService) ListActiveCategories ¶
func (s *FindingSourceService) ListActiveCategories(ctx context.Context) ([]*findingsource.Category, error)
ListActiveCategories lists all active categories.
func (*FindingSourceService) ListActiveFindingSources ¶
func (s *FindingSourceService) ListActiveFindingSources(ctx context.Context) ([]*findingsource.FindingSource, error)
ListActiveFindingSources lists all active finding sources.
func (*FindingSourceService) ListActiveFindingSourcesByCategory ¶
func (s *FindingSourceService) ListActiveFindingSourcesByCategory(ctx context.Context, categoryID string) ([]*findingsource.FindingSource, error)
ListActiveFindingSourcesByCategory lists active finding sources by category.
func (*FindingSourceService) ListActiveFindingSourcesWithCategory ¶
func (s *FindingSourceService) ListActiveFindingSourcesWithCategory(ctx context.Context) ([]*findingsource.FindingSourceWithCategory, error)
ListActiveFindingSourcesWithCategory lists all active finding sources with their categories.
func (*FindingSourceService) ListCategories ¶
func (s *FindingSourceService) ListCategories(ctx context.Context, filter findingsource.CategoryFilter, page pagination.Pagination) (pagination.Result[*findingsource.Category], error)
ListCategories lists categories with pagination.
func (*FindingSourceService) ListFindingSources ¶
func (s *FindingSourceService) ListFindingSources(ctx context.Context, filter findingsource.Filter, opts findingsource.ListOptions, page pagination.Pagination) (pagination.Result[*findingsource.FindingSource], error)
ListFindingSources lists finding sources with filtering and pagination.
func (*FindingSourceService) ListFindingSourcesWithCategory ¶
func (s *FindingSourceService) ListFindingSourcesWithCategory(ctx context.Context, filter findingsource.Filter, opts findingsource.ListOptions, page pagination.Pagination) (pagination.Result[*findingsource.FindingSourceWithCategory], error)
ListFindingSourcesWithCategory lists finding sources with their categories.
type GetFindingStatsInput ¶
type GetFindingStatsInput struct {
TenantID string
ActingUserID string
IsAdmin bool
// AssetID — when non-empty, restrict the stats to findings on this
// specific asset. Used by /findings?assetId=… so the severity cards
// match the filtered table.
AssetID string
}
GetFindingStatsInput represents input for getting finding stats with data scope.
type ImportResult ¶
type ImportResult struct {
Total int `json:"total"`
Created int `json:"created"`
Skipped int `json:"skipped"`
Errors int `json:"errors"`
Messages []string `json:"messages,omitempty"`
}
ImportResult contains the result of an import operation.
type KEVRepository ¶
type KEVRepository interface {
GetByCVEIDs(ctx context.Context, cveIDs []string) (map[string]KEVData, error)
}
KEVRepository provides KEV catalog lookups.
type ListFindingsInput ¶
type ListFindingsInput struct {
TenantID string `validate:"required,uuid"`
AssetID string `validate:"omitempty,uuid"`
BranchID string `validate:"omitempty,uuid"`
ComponentID string `validate:"omitempty,uuid"`
VulnerabilityID string `validate:"omitempty,uuid"`
Severities []string `validate:"max=5,dive,severity"`
Statuses []string `validate:"max=10,dive,finding_status"`
ExcludeStatuses []string `validate:"max=10,dive,finding_status"`
Sources []string `validate:"max=5,dive,finding_source"`
ToolName string `validate:"max=100"`
RuleID string `validate:"max=255"`
ScanID string `validate:"max=100"`
FilePath string `validate:"max=500"`
Search string `validate:"max=255"` // Full-text search across title, description, and file path
Sort string `validate:"max=100"` // Sort field (e.g., "-severity", "created_at")
Page int `validate:"min=0"`
PerPage int `validate:"min=0,max=100"`
// Layer 2: Data Scope
ActingUserID string // From JWT context
IsAdmin bool // True for owner/admin (bypasses data scope)
}
ListFindingsInput represents the input for listing findings.
type ListVulnerabilitiesInput ¶
type ListVulnerabilitiesInput struct {
CVEIDs []string `validate:"max=50,dive,max=20"`
Severities []string `validate:"max=5,dive,severity"`
MinCVSS *float64 `validate:"omitempty,min=0,max=10"`
MaxCVSS *float64 `validate:"omitempty,min=0,max=10"`
MinEPSS *float64 `validate:"omitempty,min=0,max=1"`
ExploitAvailable *bool
CISAKEVOnly *bool
Statuses []string `validate:"max=5,dive,vulnerability_status"`
Search string `validate:"max=255"` // Full-text search across CVE ID and description
Sort string `validate:"max=100"` // Sort field (e.g., "-cvss_score", "cve_id")
Page int `validate:"min=0"`
PerPage int `validate:"min=0,max=100"`
}
ListVulnerabilitiesInput represents the input for listing vulnerabilities.
type PriorityAuditEntry ¶
type PriorityAuditEntry struct {
TenantID shared.ID
FindingID shared.ID
PreviousClass *vulnerability.PriorityClass
NewClass vulnerability.PriorityClass
Reason string
Source string // "auto", "rule", "manual"
RuleID *shared.ID
ActorID *shared.ID
}
PriorityAuditEntry represents a priority change log entry.
type PriorityAuditRepository ¶
type PriorityAuditRepository interface {
LogChange(ctx context.Context, entry PriorityAuditEntry) error
}
PriorityAuditRepository records priority changes.
type PriorityChangeEvent ¶
type PriorityChangeEvent struct {
TenantID shared.ID
FindingID shared.ID
PreviousClass *vulnerability.PriorityClass // nil for first classification
NewClass vulnerability.PriorityClass
Reason string
Source string // "auto" | "rule" | "sweep" | "manual"
RuleID *shared.ID
At time.Time
}
PriorityChangeEvent is emitted whenever a finding's priority class transitions to a new value. Downstream consumers (notification service, assignment-rule service, dashboard live feed) subscribe via the outbox.
(F3, B1, B2): emission is the mechanism that wires the reclassification sweep to the rest of the system. Without this event, a priority change is a silent dashboard update — an operator can miss that a P3 just became P0.
type PriorityChangePublisher ¶
type PriorityChangePublisher interface {
Publish(ctx context.Context, event PriorityChangeEvent) error
}
PriorityChangePublisher delivers priority-change events to downstream consumers, typically by inserting into the notification outbox. Optional — when nil, classification still runs but no event is fired.
type PriorityClassificationService ¶
type PriorityClassificationService struct {
// contains filtered or unexported fields
}
PriorityClassificationService orchestrates finding priority classification. It enriches findings with EPSS/KEV data, evaluates override rules, and applies the default CTEM classification logic.
func NewPriorityClassificationService ¶
func NewPriorityClassificationService( findingRepo vulnerability.FindingRepository, assetRepo asset.Repository, epssRepo EPSSRepository, kevRepo KEVRepository, ruleRepo PriorityRuleRepository, auditRepo PriorityAuditRepository, log *logger.Logger, ) *PriorityClassificationService
NewPriorityClassificationService creates a new service.
func (*PriorityClassificationService) ClassifyFinding ¶
func (s *PriorityClassificationService) ClassifyFinding( ctx context.Context, tenantID shared.ID, finding *vulnerability.Finding, assetEntity *asset.Asset, ) error
ClassifyFinding computes priority for a single finding.
(O1 invariant): emits ctem_stage_* metrics so dashboards and alert rules have real numbers for the Prioritization stage. Skipped on manual overrides — those bypass the stage entirely.
func (*PriorityClassificationService) EnrichAndClassifyBatch ¶
func (s *PriorityClassificationService) EnrichAndClassifyBatch( ctx context.Context, tenantID shared.ID, findings []*vulnerability.Finding, assets map[shared.ID]*asset.Asset, ) error
EnrichAndClassifyBatch enriches findings with EPSS/KEV and classifies priority. Used after ingest to process a batch of new/updated findings.
func (*PriorityClassificationService) SetChangePublisher ¶
func (s *PriorityClassificationService) SetChangePublisher(p PriorityChangePublisher)
SetChangePublisher wires the priority-change event publisher. Safe to call after construction; nil disables publishing.
func (*PriorityClassificationService) SetControlLookup ¶
func (s *PriorityClassificationService) SetControlLookup(lookup CompensatingControlLookup)
SetControlLookup wires the compensating control lookup for priority calculation.
func (*PriorityClassificationService) SetPriorityFloodGuard ¶
func (s *PriorityClassificationService) SetPriorityFloodGuard(g *PriorityFloodGuard)
SetPriorityFloodGuard wires the anti-flap budget used to suppress downstream fan-out on top-class bursts from noisy scanners. Nil disables the guard. Safe to call after construction.
type PriorityFloodConfig ¶
type PriorityFloodConfig struct {
// ProtectedClass is the priority class whose downstream fan-out
// is capped. Defaults to vulnerability.PriorityP0 — the highest
// class is the one that actually moves SLA clocks and pages
// humans, so flooding there is the acute failure mode.
ProtectedClass vulnerability.PriorityClass
// MaxPerHour is the ceiling of newly-classified findings at the
// protected class per tenant per rolling hour at which we start
// suppressing downstream side effects. Default 50 — chosen
// because a single tenant realistically cannot action more than
// ~50 of the top class per hour.
MaxPerHour int
// Now is injectable for deterministic tests.
Now func() time.Time
}
PriorityFloodConfig tunes the guard. Zero values take documented defaults.
type PriorityFloodGuard ¶
type PriorityFloodGuard struct {
// contains filtered or unexported fields
}
PriorityFloodGuard is per-process in-memory. A future iteration moves it to Redis for cross-replica dedup; as long as there is ONE background worker doing classification (the sweep controller), in-memory is sufficient.
func NewPriorityFloodGuard ¶
func NewPriorityFloodGuard(cfg PriorityFloodConfig) *PriorityFloodGuard
NewPriorityFloodGuard constructs the guard with defaults.
func (*PriorityFloodGuard) CurrentUsage ¶
func (g *PriorityFloodGuard) CurrentUsage(tenantID shared.ID) int
CurrentUsage exposes the rolling-hour count for dashboards.
func (*PriorityFloodGuard) Refund ¶
func (g *PriorityFloodGuard) Refund(tenantID shared.ID)
Refund returns a slot to the tenant's budget. Used when the caller's fan-out fails and will retry — otherwise a delivery failure would permanently burn the slot.
func (*PriorityFloodGuard) ShouldFanOut ¶
func (g *PriorityFloodGuard) ShouldFanOut( ctx context.Context, tenantID shared.ID, class vulnerability.PriorityClass, ) (bool, error)
ShouldFanOut reports whether the downstream side effects (Jira, outbox, fast-lane queue) should run for a newly-classified finding at the guard's protected class.
Returns (true, nil) under budget — record AND fire. Returns (false, ErrPriorityFloodSuppressed) over budget — record only.
A classification that is NOT the protected class short-circuits immediately and the budget is not charged.
type PriorityRuleRepository ¶
type PriorityRuleRepository interface {
ListActiveByTenant(ctx context.Context, tenantID shared.ID) ([]*vulnerability.PriorityOverrideRule, error)
}
PriorityRuleRepository provides override rule lookups.
type RejectApprovalInput ¶
type RejectApprovalInput struct {
TenantID string `json:"tenant_id" validate:"required,uuid"`
ApprovalID string `json:"approval_id" validate:"required,uuid"`
RejectedBy string `json:"rejected_by" validate:"required,uuid"`
Reason string `json:"reason" validate:"required,min=1,max=2000"`
}
RejectApprovalInput represents the input for rejecting a status change.
type RejectByFilterInput ¶
type RejectByFilterInput struct {
Filter vulnerability.FindingFilter
Reason string
}
RejectByFilterInput is the input for bulk reject by filter.
type RequestApprovalInput ¶
type RequestApprovalInput struct {
TenantID string `json:"tenant_id" validate:"required,uuid"`
FindingID string `json:"finding_id" validate:"required,uuid"`
RequestedStatus string `json:"requested_status" validate:"required"`
Justification string `json:"justification" validate:"required,min=1,max=2000"`
RequestedBy string `json:"requested_by" validate:"required,uuid"`
ExpiresAt *string `json:"expires_at"`
}
RequestApprovalInput represents the input for requesting a status approval.
type RequestVerificationScanInput ¶
type RequestVerificationScanInput struct {
FindingID string
ScannerName string // required if WorkflowID is empty
WorkflowID string // required if ScannerName is empty
}
RequestVerificationScanInput is the input for requesting a verification scan.
type RequestVerificationScanResult ¶
type RequestVerificationScanResult struct {
FindingID string `json:"finding_id"`
AssetID string `json:"asset_id"`
AssetName string `json:"asset_name"`
PipelineRunID string `json:"pipeline_run_id"`
ScanID string `json:"scan_id"`
}
RequestVerificationScanResult is the result of requesting a verification scan.
type TenantLister ¶
type TenantLister interface {
// ListActiveTenantIDs returns all active tenant IDs for batch processing.
ListActiveTenantIDs(ctx context.Context) ([]shared.ID, error)
}
TenantLister provides a list of active tenant IDs.
type UpdateCommentInput ¶
type UpdateCommentInput struct {
Content string `validate:"required,min=1,max=10000"`
}
UpdateCommentInput represents the input for updating a comment.
type UpdateFindingStatusInput ¶
type UpdateFindingStatusInput struct {
Status string `validate:"required,finding_status"`
Resolution string `validate:"max=1000"`
ActorID string // Authenticated user ID from middleware (required for audit trail and resolved_by)
HasVerifyPermission bool // True if user has findings:verify permission (for direct resolve guard)
}
UpdateFindingStatusInput represents the input for updating a finding's status.
type UpdateVulnerabilityInput ¶
type UpdateVulnerabilityInput struct {
Title *string `validate:"omitempty,min=1,max=500"`
Description *string `validate:"omitempty,max=10000"`
Severity *string `validate:"omitempty,severity"`
CVSSScore *float64 `validate:"omitempty,min=0,max=10"`
CVSSVector *string `validate:"omitempty,max=100"`
EPSSScore *float64 `validate:"omitempty,min=0,max=1"`
EPSSPercentile *float64 `validate:"omitempty,min=0,max=1"`
ExploitAvailable *bool
ExploitMaturity *string `validate:"omitempty,exploit_maturity"`
FixedVersions []string `validate:"omitempty,max=50,dive,max=100"`
Remediation *string `validate:"omitempty,max=5000"`
Status *string `validate:"omitempty,vulnerability_status"`
}
UpdateVulnerabilityInput represents the input for updating a vulnerability.
type VerificationScanTrigger ¶
type VerificationScanTrigger interface {
// TriggerVerificationScan launches a quick scan on the given targets.
// targets is a list of asset identifiers (names / hostnames / URLs).
// Returns the pipeline run ID and scan ID on success.
TriggerVerificationScan(ctx context.Context, tenantID, createdBy, scannerName, workflowID string, targets []string) (pipelineRunID, scanID string, err error)
}
VerificationScanTrigger is the interface for triggering targeted verification scans. Implemented by the scan.Service; kept as interface to avoid import cycles.
type VerifyByFilterInput ¶
type VerifyByFilterInput struct {
Filter vulnerability.FindingFilter
Note string
}
VerifyByFilterInput is the input for bulk verify by filter.
type VulnerabilityService ¶
type VulnerabilityService struct {
// contains filtered or unexported fields
}
VulnerabilityService handles vulnerability-related business operations.
func NewVulnerabilityService ¶
func NewVulnerabilityService( vulnRepo vulnerability.VulnerabilityRepository, findingRepo vulnerability.FindingRepository, log *logger.Logger, ) *VulnerabilityService
NewVulnerabilityService creates a new VulnerabilityService.
func (*VulnerabilityService) AddFindingComment ¶
func (s *VulnerabilityService) AddFindingComment(ctx context.Context, tenantID, findingID, authorID, content string) (*vulnerability.FindingComment, error)
AddFindingComment adds a comment to a finding. tenantID is used for IDOR prevention and activity logging.
func (*VulnerabilityService) ApproveStatus ¶
func (s *VulnerabilityService) ApproveStatus(ctx context.Context, input ApproveStatusInput) (*vulnerability.Approval, error)
ApproveStatus approves a pending status change request and applies the status change.
func (*VulnerabilityService) AssignFinding ¶
func (s *VulnerabilityService) AssignFinding(ctx context.Context, findingID, tenantID, userID, assignerID string) (*vulnerability.Finding, error)
AssignFinding assigns a finding to a user.
func (*VulnerabilityService) BulkAssignFindings ¶
func (s *VulnerabilityService) BulkAssignFindings(ctx context.Context, tenantID string, input BulkAssignInput) (*BulkUpdateResult, error)
BulkAssignFindings assigns multiple findings to a user.
func (*VulnerabilityService) BulkUpdateFindingStatus ¶
func (s *VulnerabilityService) BulkUpdateFindingStatus(ctx context.Context, tenantID shared.ID, ids []shared.ID, status vulnerability.FindingStatus, resolution string, resolvedBy *shared.ID) error
BulkUpdateFindingStatus updates the status of multiple findings. Pentest findings are excluded — they must be managed via the pentest module.
func (*VulnerabilityService) BulkUpdateFindingsStatus ¶
func (s *VulnerabilityService) BulkUpdateFindingsStatus(ctx context.Context, tenantID string, input BulkUpdateStatusInput) (*BulkUpdateResult, error)
BulkUpdateFindingsStatus updates the status of multiple findings. Optimized: batch-fetches all findings in 1 query, validates transitions in-memory, then batch-updates valid ones in 1 query. Reduces N+1 to 2 queries total.
func (*VulnerabilityService) CancelApproval ¶
func (s *VulnerabilityService) CancelApproval(ctx context.Context, input CancelApprovalInput) (*vulnerability.Approval, error)
CancelApproval cancels a pending approval request. Only the requester can cancel.
func (*VulnerabilityService) ClassifyFinding ¶
func (s *VulnerabilityService) ClassifyFinding(ctx context.Context, findingID, tenantID string, input ClassifyFindingInput) (*vulnerability.Finding, error)
ClassifyFinding sets classification data on a finding.
func (*VulnerabilityService) CountAssetFindings ¶
func (s *VulnerabilityService) CountAssetFindings( ctx context.Context, tenantID string, assetID string, ) (int64, error)
CountAssetFindings counts findings for an asset. tenantID is used for IDOR prevention - ensures the findings belong to the caller's tenant.
func (*VulnerabilityService) CountOpenAssetFindings ¶
func (s *VulnerabilityService) CountOpenAssetFindings( ctx context.Context, tenantID string, assetID string, ) (int64, error)
CountOpenAssetFindings counts open findings for an asset. tenantID is used for IDOR prevention - ensures the findings belong to the caller's tenant.
func (*VulnerabilityService) CreateFinding ¶
func (s *VulnerabilityService) CreateFinding(ctx context.Context, input CreateFindingInput) (*vulnerability.Finding, error)
CreateFinding creates a new finding.
func (*VulnerabilityService) CreateVulnerability ¶
func (s *VulnerabilityService) CreateVulnerability(ctx context.Context, input CreateVulnerabilityInput) (*vulnerability.Vulnerability, error)
CreateVulnerability creates a new vulnerability.
func (*VulnerabilityService) DeleteAssetFindings ¶
func (s *VulnerabilityService) DeleteAssetFindings( ctx context.Context, tenantID string, assetID string, ) error
DeleteAssetFindings deletes all findings for an asset. tenantID is used for IDOR prevention - ensures the findings belong to the caller's tenant.
func (*VulnerabilityService) DeleteFinding ¶
func (s *VulnerabilityService) DeleteFinding(ctx context.Context, findingID string, tenantID string) error
DeleteFinding deletes a finding by ID. tenantID is used for IDOR prevention - ensures the finding belongs to the caller's tenant.
func (*VulnerabilityService) DeleteFindingComment ¶
func (s *VulnerabilityService) DeleteFindingComment(ctx context.Context, tenantID, commentID, authorID string) error
DeleteFindingComment deletes a comment. tenantID scopes the lookup and the DELETE WHERE clause — closes the same IDOR vector as UpdateFindingComment.
func (*VulnerabilityService) DeleteVulnerability ¶
func (s *VulnerabilityService) DeleteVulnerability(ctx context.Context, vulnID string) error
DeleteVulnerability deletes a vulnerability by ID.
func (*VulnerabilityService) GetFinding ¶
func (s *VulnerabilityService) GetFinding(ctx context.Context, tenantID, findingID string) (*vulnerability.Finding, error)
GetFinding retrieves a finding by ID. tenantID is used for IDOR prevention - ensures the finding belongs to the caller's tenant.
func (*VulnerabilityService) GetFindingCountsByScanID ¶
func (s *VulnerabilityService) GetFindingCountsByScanID(ctx context.Context, tenantID, scanID string) (vulnerability.SeverityCounts, error)
GetFindingCountsByScanID returns the count of findings by severity for a scan. Used for quality gate evaluation.
func (*VulnerabilityService) GetFindingStats ¶
func (s *VulnerabilityService) GetFindingStats(ctx context.Context, tenantID string) (*vulnerability.FindingStats, error)
GetFindingStats retrieves aggregated statistics for findings of a tenant.
func (*VulnerabilityService) GetFindingStatsWithScope ¶
func (s *VulnerabilityService) GetFindingStatsWithScope(ctx context.Context, input GetFindingStatsInput) (*vulnerability.FindingStats, error)
GetFindingStatsWithScope retrieves stats with optional data scope enforcement.
func (*VulnerabilityService) GetFindingWithScope ¶
func (s *VulnerabilityService) GetFindingWithScope(ctx context.Context, tenantID, findingID, actingUserID string, isAdmin bool) (*vulnerability.Finding, error)
GetFindingWithScope retrieves a finding with optional data scope enforcement. Non-admin users with group assignments can only access findings for assets in their groups. Security: fail-closed — any error during scope check denies access. Returns ErrNotFound (not ErrForbidden) to prevent information disclosure.
func (*VulnerabilityService) GetVulnerability ¶
func (s *VulnerabilityService) GetVulnerability(ctx context.Context, vulnID string) (*vulnerability.Vulnerability, error)
GetVulnerability retrieves a vulnerability by ID.
func (*VulnerabilityService) GetVulnerabilityByCVE ¶
func (s *VulnerabilityService) GetVulnerabilityByCVE(ctx context.Context, cveID string) (*vulnerability.Vulnerability, error)
GetVulnerabilityByCVE retrieves a vulnerability by CVE ID.
func (*VulnerabilityService) ListAssetFindings ¶
func (s *VulnerabilityService) ListAssetFindings( ctx context.Context, tenantID string, assetID string, sort string, page, perPage int, ) (pagination.Result[*vulnerability.Finding], error)
ListAssetFindings retrieves findings for a specific asset. tenantID is used for IDOR prevention - ensures the findings belong to the caller's tenant.
func (*VulnerabilityService) ListFindingApprovals ¶
func (s *VulnerabilityService) ListFindingApprovals(ctx context.Context, tenantID, findingID string) ([]*vulnerability.Approval, error)
ListFindingApprovals lists all approvals for a finding.
func (*VulnerabilityService) ListFindingComments ¶
func (s *VulnerabilityService) ListFindingComments(ctx context.Context, findingID string) ([]*vulnerability.FindingComment, error)
ListFindingComments retrieves all comments for a finding.
func (*VulnerabilityService) ListFindings ¶
func (s *VulnerabilityService) ListFindings(ctx context.Context, input ListFindingsInput) (pagination.Result[*vulnerability.Finding], error)
ListFindings retrieves findings with filtering and pagination.
func (*VulnerabilityService) ListPendingApprovals ¶
func (s *VulnerabilityService) ListPendingApprovals(ctx context.Context, tenantID string, page, perPage int) (pagination.Result[*vulnerability.Approval], error)
ListPendingApprovals lists all pending approvals for a tenant.
func (*VulnerabilityService) ListVulnerabilities ¶
func (s *VulnerabilityService) ListVulnerabilities(ctx context.Context, input ListVulnerabilitiesInput) (pagination.Result[*vulnerability.Vulnerability], error)
ListVulnerabilities retrieves vulnerabilities with filtering and pagination.
func (*VulnerabilityService) RejectApproval ¶
func (s *VulnerabilityService) RejectApproval(ctx context.Context, input RejectApprovalInput) (*vulnerability.Approval, error)
RejectApproval rejects a pending status change request.
func (*VulnerabilityService) RequestApproval ¶
func (s *VulnerabilityService) RequestApproval(ctx context.Context, input RequestApprovalInput) (*vulnerability.Approval, error)
RequestApproval creates a new pending approval request for a status change.
func (*VulnerabilityService) SetAITriageService ¶
func (s *VulnerabilityService) SetAITriageService(svc *aitriage.AITriageService)
SetAITriageService sets the AI triage service for auto-triage on finding creation.
func (*VulnerabilityService) SetAccessControlRepository ¶
func (s *VulnerabilityService) SetAccessControlRepository(repo accesscontrol.Repository)
SetAccessControlRepository sets the access control repository for Layer 2 data scope checks.
func (*VulnerabilityService) SetActivityService ¶
func (s *VulnerabilityService) SetActivityService(svc *activity.FindingActivityService)
SetActivityService sets the activity service for audit trail tracking. When set, the service will automatically record activities for finding changes.
func (*VulnerabilityService) SetApprovalRepository ¶
func (s *VulnerabilityService) SetApprovalRepository(repo vulnerability.ApprovalRepository)
SetApprovalRepository sets the approval repository for status approval workflow.
func (*VulnerabilityService) SetAssignmentEngine ¶
func (s *VulnerabilityService) SetAssignmentEngine(engine *assignment.Engine)
SetAssignmentEngine sets the assignment engine for auto-routing findings to groups.
func (*VulnerabilityService) SetCommentRepository ¶
func (s *VulnerabilityService) SetCommentRepository(repo vulnerability.FindingCommentRepository)
SetCommentRepository sets the comment repository for comment operations. This is optional and can be called after service creation.
func (*VulnerabilityService) SetDataFlowRepository ¶
func (s *VulnerabilityService) SetDataFlowRepository(repo vulnerability.DataFlowRepository)
SetDataFlowRepository sets the data flow repository for loading data flow traces.
func (*VulnerabilityService) SetFindingNotifier ¶
func (s *VulnerabilityService) SetFindingNotifier(notifier FindingNotifier)
SetFindingNotifier sets the notifier for new findings. Deprecated: Use SetOutboxService for reliable transactional notifications.
func (*VulnerabilityService) SetFindingTags ¶
func (s *VulnerabilityService) SetFindingTags(ctx context.Context, findingID, tenantID string, tags []string) (*vulnerability.Finding, error)
SetFindingTags sets tags on a finding.
func (*VulnerabilityService) SetOutboxService ¶
func (s *VulnerabilityService) SetOutboxService(db *sql.DB, svc *outbox.Service)
SetOutboxService sets the notification service for transactional outbox pattern. When set, notifications are enqueued in the same transaction as finding creation, ensuring reliable delivery even if the server crashes.
func (*VulnerabilityService) SetUserNotificationService ¶
func (s *VulnerabilityService) SetUserNotificationService(svc *integration.NotificationService)
SetUserNotificationService sets the in-app notification service for user-facing notifications.
func (*VulnerabilityService) SetUserRepository ¶
func (s *VulnerabilityService) SetUserRepository(repo user.Repository)
SetUserRepository sets the user repository for user lookup (e.g., for activity recording).
func (*VulnerabilityService) TriageFinding ¶
func (s *VulnerabilityService) TriageFinding(ctx context.Context, findingID, tenantID, userID, reason string) (*vulnerability.Finding, error)
TriageFinding confirms a finding (triage = confirm the finding is real). This is a convenience method that transitions status from "new" to "confirmed". For other status changes, use UpdateFindingStatus.
func (*VulnerabilityService) UnassignFinding ¶
func (s *VulnerabilityService) UnassignFinding(ctx context.Context, findingID, tenantID, actorID string) (*vulnerability.Finding, error)
UnassignFinding removes the assignment from a finding.
func (*VulnerabilityService) UpdateFindingComment ¶
func (s *VulnerabilityService) UpdateFindingComment(ctx context.Context, tenantID, commentID, authorID, content string) (*vulnerability.FindingComment, error)
UpdateFindingComment updates a comment's content. tenantID scopes the lookup so a user in tenant A cannot resolve a commentID owned by tenant B — closes the IDOR vector where the author-ID short-circuit (authorID=="") would let an admin-path bypass the per-row owner check.
func (*VulnerabilityService) UpdateFindingSeverity ¶
func (s *VulnerabilityService) UpdateFindingSeverity(ctx context.Context, findingID, tenantID, severityStr, actorID string) (*vulnerability.Finding, error)
UpdateFindingSeverity updates a finding's severity.
func (*VulnerabilityService) UpdateFindingStatus ¶
func (s *VulnerabilityService) UpdateFindingStatus(ctx context.Context, findingID string, tenantID string, input UpdateFindingStatusInput) (*vulnerability.Finding, error)
UpdateFindingStatus updates a finding's status. tenantID is used for IDOR prevention - ensures the finding belongs to the caller's tenant.
func (*VulnerabilityService) UpdateVulnerability ¶
func (s *VulnerabilityService) UpdateVulnerability(ctx context.Context, vulnID string, input UpdateVulnerabilityInput) (*vulnerability.Vulnerability, error)
UpdateVulnerability updates an existing vulnerability.
func (*VulnerabilityService) VerifyFinding ¶
func (s *VulnerabilityService) VerifyFinding(ctx context.Context, findingID, tenantID, userID string) (*vulnerability.Finding, error)
VerifyFinding marks a resolved finding as verified.