Documentation
¶
Overview ¶
Package reclassify provides the runtime glue that connects priority-change producers (threat-intel refresh, control CRUD, rule CRUD) to the PriorityReclassifyController's queue/Reclassifier contracts.
The package lives under internal/app so the app-layer wire sites (services.go) can see it directly; controller itself imports app for unrelated reasons, so placing the adapters in `app` directly would introduce a cycle. Keep new code here.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type MemoryQueue ¶
type MemoryQueue struct {
// contains filtered or unexported fields
}
MemoryQueue is a minimal in-process ReclassifyQueue. It is intentionally unbounded (slice-backed) but tolerates burst enqueues cheaply — the controller drains at Interval=5m with BatchSize=64, so backlog in practice is small. When the API scales beyond a single replica, swap this for a Redis or Postgres queue; the interface is stable.
Order: FIFO. Dedup: none (controller-side dedup is cheaper — two enqueues for the same (tenant,asset) do the same work twice but don't produce duplicate priority_changed events thanks to the publisher's "no transition = no publish" guard).
func (*MemoryQueue) DequeueBatch ¶
func (q *MemoryQueue) DequeueBatch(_ context.Context, max int) ([]controller.ReclassifyRequest, error)
DequeueBatch pops up to max requests. Returns an empty slice (nil error) when empty.
func (*MemoryQueue) Enqueue ¶
func (q *MemoryQueue) Enqueue(_ context.Context, req controller.ReclassifyRequest) error
Enqueue adds a request. Safe for concurrent use.
func (*MemoryQueue) Len ¶
func (q *MemoryQueue) Len() int
Len is exposed for observability/dashboards. Safe for concurrent use.
type PriorityClassifier ¶
type PriorityClassifier interface {
ClassifyFinding(ctx context.Context, tenantID shared.ID, finding *vulnerability.Finding, a *asset.Asset) error
}
PriorityClassifier is the narrow surface the reclassifier needs from PriorityClassificationService. Narrow to keep tests cheap.
type Reclassifier ¶
type Reclassifier struct {
// contains filtered or unexported fields
}
Reclassifier implements controller.Reclassifier. It turns a scope (AssetIDs, CVEIDs) into concrete Finding+Asset pairs and delegates to the classifier. The classifier already handles priority_changed event emission via its attached publisher — so a sweep that re-confirms the same class is silent, and a sweep that moves a class fans out correctly.
The current impl handles the most-common sweep scope: AssetIDs (produced by control-change and asset-change publishers). A CVEIDs branch (produced by EPSS/KEV refreshes) is a follow-up — the threat intel flow already enqueues with CVEIDs, so this branch will be added alongside the next wire of that producer.
func NewReclassifier ¶
func NewReclassifier( findings vulnerability.FindingRepository, assets asset.Repository, classifier PriorityClassifier, log *logger.Logger, ) *Reclassifier
NewReclassifier wires deps.
func (*Reclassifier) ReclassifyForRequest ¶
func (r *Reclassifier) ReclassifyForRequest( ctx context.Context, req controller.ReclassifyRequest, ) (int, error)
ReclassifyForRequest satisfies controller.Reclassifier.
Strategy:
- If req.AssetIDs is non-empty → iterate each asset, page findings, classify. This is the control-change / asset-change path.
- Otherwise → no-op with a warn (we only drain scoped requests for now; unscoped "reclassify everything" would be a footgun without a rate limiter).