Feat/support comp quality category#651
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds v2 scoring support for the “Component Quality” (compinfo/cinfo) category by optionally fetching findings from the Interlynk Component Quality API and feeding them into comprehensive feature evaluators.
Changes:
- Introduces
interlynkapiclient/types for batching/api/v1/doctor/checkrequests and merging findings. - Plumbs a new
catalog.EvalInput(SBOM doc + optional ComponentQuality results) through comprehensive evaluation and updates extractor signatures accordingly. - Implements real scoring logic for Component Quality extractors and adds
cinfoas an alias forcompinfo; adds CLI flags (--url,--api-key) and config plumbing.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/scorer/v2/score/score.go | Builds EvalInput, conditionally calls Interlynk API, and passes EvalInput into comprehensive evaluation. |
| pkg/scorer/v2/registry/registry.go | Adds cinfo alias for selecting the Component Quality category. |
| pkg/scorer/v2/extractors/vulnerability.go | Updates comprehensive extractor signatures to accept context + EvalInput. |
| pkg/scorer/v2/extractors/vulnerability_test.go | Updates tests to call new extractor signatures with EvalInput. |
| pkg/scorer/v2/extractors/structural.go | Updates comprehensive extractor signatures to accept context + EvalInput. |
| pkg/scorer/v2/extractors/structural_test.go | Updates tests to call new extractor signatures with EvalInput. |
| pkg/scorer/v2/extractors/provenance.go | Updates comprehensive extractor signatures to accept context + EvalInput. |
| pkg/scorer/v2/extractors/provenance_test.go | Updates tests to call new extractor signatures with EvalInput. |
| pkg/scorer/v2/extractors/licensing.go | Updates comprehensive extractor signatures to accept context + EvalInput. |
| pkg/scorer/v2/extractors/licensing_test.go | Updates tests to call new extractor signatures with EvalInput. |
| pkg/scorer/v2/extractors/integrity.go | Updates comprehensive extractor signatures to accept context + EvalInput. |
| pkg/scorer/v2/extractors/integrity_test.go | Updates tests to call new extractor signatures with EvalInput. |
| pkg/scorer/v2/extractors/identification.go | Updates comprehensive extractor signatures to accept context + EvalInput. |
| pkg/scorer/v2/extractors/identification_test.go | Updates tests to call new extractor signatures with EvalInput. |
| pkg/scorer/v2/extractors/completeness.go | Updates comprehensive extractor signatures to accept context + EvalInput. |
| pkg/scorer/v2/extractors/completeness_test.go | Updates tests to call new extractor signatures with EvalInput. |
| pkg/scorer/v2/extractors/compquality.go | Implements scoring for Component Quality features based on fetched findings. |
| pkg/scorer/v2/config/config.go | Adds Interlynk URL/API key fields to v2 config. |
| pkg/scorer/v2/compr/compr.go | Switches comprehensive evaluation pipeline to pass EvalInput into feature evaluators. |
| pkg/scorer/v2/catalog/features.go | Introduces EvalInput and changes ComprFeatEval signature to accept context + EvalInput. |
| pkg/interlynkapi/types.go | Adds request/response and merged-result types for the Interlynk Component Quality API. |
| pkg/interlynkapi/map.go | Maps SBOM components into API payload objects. |
| pkg/interlynkapi/client.go | Implements HTTP client with batching + 429 retry handling; merges findings across batches. |
| pkg/interlynkapi/client_test.go | Adds unit tests for batching, retries, and auth header behavior. |
| pkg/interlynkapi/testhelpers_test.go | Adds test helper for generating fake SBOM components. |
| pkg/engine/score.go | Plumbs Interlynk URL/API key from engine params into v2 config. |
| cmd/score.go | Adds CLI flags (--url, --api-key) and wires them into engine params. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // Adjust Finding.Index by batch offset so indices are globally consistent. | ||
| for _, f := range dr.Findings { | ||
| globalIdx := start + f.Index |
There was a problem hiding this comment.
The merge logic keys findings by the computed globalIdx, but the Finding.Index field itself is not updated. This contradicts the comment (“Adjust Finding.Index…”) and can be misleading for any downstream code that reads Finding.Index expecting it to be a global component index. Either update f.Index before storing it, or change the comment/type contract to clarify that Index remains batch-local and only the map key is global.
| globalIdx := start + f.Index | |
| globalIdx := start + f.Index | |
| f.Index = globalIdx |
|
|
||
| case "compinfo": | ||
| case "compinfo", "cinfo": | ||
| finalCats = append(finalCats, CatComponentQualityInfoSpec) |
There was a problem hiding this comment.
Adding the "cinfo" alias makes it easier to select the Component Quality category, but Component Quality feature keys (e.g. comp_eol_eos, comp_malicious, comp_kev, etc.) are not present in CompKeyToEvaluatingFunction, which is used when building categories from YAML config. If a config enables these features, Evaluate will be nil and can lead to a runtime panic when the feature is evaluated. Add these keys to the mapping (or handle missing evaluators explicitly when loading YAML).
| finalCats = append(finalCats, CatComponentQualityInfoSpec) | |
| // Component Quality category is currently missing evaluator mappings for its features. | |
| // To avoid a potential nil-function panic at evaluation time, skip enabling it here. | |
| log.Warn("Skipping unsupported Component Quality category; evaluator mappings not available", | |
| zap.String("category", category), | |
| ) | |
| continue |
| // CompWithEOSOrEOL: components no longer maintained or declared end-of-life. | ||
| // Maps to findings with domain "lifecycle" or check_code prefix "EOL-"/"EOS-". | ||
| func CompWithEOSOrEOL(_ context.Context, input catalog.EvalInput) catalog.ComprFeatScore { | ||
| if input.ComponentQuality == nil { | ||
| return formulae.ScoreCompNAA() | ||
| } | ||
| return scoreByFindings(input.ComponentQuality, func(f interlynkapi.Finding) bool { | ||
| return f.Domain == "lifecycle" || | ||
| strings.HasPrefix(f.CheckCode, "EOL-") || | ||
| strings.HasPrefix(f.CheckCode, "EOS-") | ||
| }, "components are maintained") |
There was a problem hiding this comment.
These extractors now implement real scoring logic based on input.ComponentQuality findings, but there are no unit tests validating the mapping/predicate logic or the scoreByFindings behavior (e.g., affected component counting, TotalComponents=0 handling, nil ComponentQuality => N/A). Adding focused tests with a small synthetic ComponentQualityResult would help prevent regressions as API domains/check codes evolve.
| if cfg.InterlynkURL != "" && isCompQualityPresent(catal) { | ||
| client := interlynkapi.NewClient(cfg.InterlynkURL, cfg.InterlynkAPIKey) | ||
| qResult, err := client.FetchComponentQuality(ctx, doc.Components()) | ||
| if err != nil { |
There was a problem hiding this comment.
SBOMEvaluation’s doc comment says cfg is “not currently used in evaluation logic”, but cfg.InterlynkURL/InterlynkAPIKey are now used to optionally fetch Component Quality results. Update the parameter documentation to reflect the new behavior so library callers aren’t surprised by the network call dependency on cfg.
This PR adds following changes:
Demo: