Skip to content

Refactor to support related purl#51

Merged
scanoss-qg merged 3 commits into
mainfrom
SP4351-SourcePurlInfo
Jun 2, 2026
Merged

Refactor to support related purl#51
scanoss-qg merged 3 commits into
mainfrom
SP4351-SourcePurlInfo

Conversation

@scanoss-qg

@scanoss-qg scanoss-qg commented Jun 2, 2026

Copy link
Copy Markdown
Contributor
  • Use go-component-helper.
  • Add support to retrieve related source purl results.
  • Improved VERSION_NOT_FOUND detection

Summary by CodeRabbit

  • New Features

    • Automatic source-code fallback: when a component lookup has no info, the system retries using repository metadata and marks results with a warning.
  • Improvements

    • Centralized component resolution for more consistent version/requirement handling across endpoints.
    • More robust version-range filtering and clearer status reporting (returns VERSION_NOT_FOUND when no version satisfies a requirement).
  • Chores

    • Updated module dependencies and lint configuration.

…results. Improved VERSION_NOT_FOUND detection
@scanoss-qg scanoss-qg requested a review from agustingroh June 2, 2026 14:50
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5dc67f3a-1eec-4d76-a8c1-8b0da9e043ab

📥 Commits

Reviewing files that changed from the base of the PR and between 83fea62 and 9c5e21c.

📒 Files selected for processing (5)
  • .golangci.yml
  • CHANGELOG.md
  • pkg/usecase/component_resolver.go
  • pkg/usecase/component_resolver_test.go
  • pkg/usecase/cryptography_search.go
💤 Files with no reviewable changes (1)
  • .golangci.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/usecase/cryptography_search.go

📝 Walkthrough

Walkthrough

Centralize component version resolution into a new resolver, remove local semver/URL-selection helpers, and refactor multiple use cases to consume resolved metadata with optional source-purl fallback and shared filtering helpers.

Changes

Component Resolution Centralization and Use Case Refactoring

Layer / File(s) Summary
Component resolver infrastructure
pkg/usecase/component_resolver.go, pkg/usecase/component_resolver_test.go
New shared resolver provides concurrent batch component version resolution, semver-range filtering, wildcard detection, and source-purl fallback extraction; includes a table-driven test for fallback eligibility.
Remove deprecated validation and selection helpers
go.mod, pkg/handlers/cryptography_support.go, pkg/models/all_urls.go, pkg/models/all_urls_test.go, pkg/models/doc.go, pkg/utils/doc.go, pkg/usecase/component_validator.go, .golangci.yml
Deleted local semver validation and URL-selection helpers (IsValidRequirement, GetUrlsByPurlNameTypeInRange, PickClosestUrls), removed related tests/docs, and updated go.mod/.golangci.yml entries.
CryptoSearch use case refactoring with source fallback
pkg/usecase/cryptography_search.go
Persist DB handle, add SourcePurl to metadata, build metadata via resolveComponentVersions(), apply source-purl fallback retry for NoInfo results, and change URL-hash selection to filter by resolved version/type.
CryptoMajor use case refactoring
pkg/usecase/cryptography_major.go
Persist DB handle, call resolveComponentVersions(), extract fillCryptoInRange() for URL + range + crypto lookup, and add source-purl fallback for components with NoInfo.
VersionsUsing use case refactoring
pkg/usecase/cryptography_versions_using.go
Replace logger with DB handle, use resolveComponentVersions() for metadata, extract fillVersionsInRange() for URL filtering and version partitioning, and add source-purl fallback when no crypto info is found.
LibraryDetections use case refactoring
pkg/usecase/library_detections.go
Persist DB handle, use resolveComponentVersions() instead of inline validation, refactor processSinglePurl() to accept explicit purl name/type and use filterUrlsInRange(), and retry with source-purl fallback on NoInfo.
Documentation and test fixtures
pkg/usecase/docs.go, pkg/models/common.go, pkg/models/tests/licenses.sql, pkg/responsebuilder/test.json, CHANGELOG.md
Update docs to reference centralized resolver, wire licenses.sql into test setup, add responsebuilder test fixture, and add 0.11.0 changelog notes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • isasmendiagus
  • mscasso-scanoss
  • agustingroh

"🐰 A Patchwork Praise"

I hopped through code, I hopped through time,
One resolver now sings in tidy rhyme.
Old helpers tucked, new paths unfurled,
Versions resolved across the world! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "Refactor to support related purl" accurately reflects the main changes: refactoring to integrate go-component-helper and adding support for source-purl fallback ("related purl"), which are core objectives of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch SP4351-SourcePurlInfo

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/usecase/cryptography_search.go (1)

45-54: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve the resolved purl type before selecting URLs.

This path now matches KB rows by ComponentName and then narrows only by exact version. Because ComponentCryptoMetadata no longer carries the resolved PurlType, same-name packages from different ecosystems can share URLs and return crypto hits for the wrong component. Please keep the resolved type in metadata and filter the selected URLs by both type and version before building urlHashes.

Also applies to: 181-203, 224-230

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/usecase/cryptography_search.go` around lines 45 - 54,
ComponentCryptoMetadata currently loses the resolved purl type which lets
same-name packages across ecosystems share SelectedURLS and produce incorrect
crypto hits; add a PurlType field to ComponentCryptoMetadata to preserve the
resolved type, populate it wherever metadata is created, and update the URL
selection logic that builds urlHashes (the code that filters
SelectedURLS/models.AllURL) to filter by both PurlType and exact Version before
constructing urlHashes; also apply the same change in the other two places noted
(the other URL-selection blocks that use SelectedURLS and build urlHashes).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/usecase/component_resolver_test.go`:
- Around line 26-83: Add a test case to TestSourcePurlForFallback that covers a
SourcePurl with Status.Success and a non-empty PurlInfo.Name but an empty
PurlInfo.PurlType (e.g., PurlInfo{Name: "jonschlinkert/word-wrap"}), and assert
that sourcePurlForFallback(component) returns ok == false; reference the structs
SourcePurl, PurlInfo, componenthelper.Component and the function
sourcePurlForFallback when adding this case to the existing tests.

In `@pkg/usecase/component_resolver.go`:
- Around line 55-59: The function sourcePurlForFallback currently returns
ok=true if c.SourcePurl.Name is non-empty but ignores c.SourcePurl.PurlType;
update the guard in sourcePurlForFallback to also require c.SourcePurl.PurlType
!= "" (and that Status.StatusCode == status.Success) before returning (name,
purlType, true) so callers never get an empty purlType; reference the
componenthelper.Component's SourcePurl, SourcePurl.Status.StatusCode,
SourcePurl.Name and SourcePurl.PurlType fields when making this change.
- Around line 93-97: The loop building ordered results assumes every key exists
in the byKey map and will silently produce zero-value componenthelper.Component
entries if a helper failed; update the assembly in component_resolver.go (the
ordered := … loop that iterates over keys and reads byKey[k]) to check map
presence (e.g., v, ok := byKey[k]) for each k, collect any missing keys, and
handle them explicitly—either log the missing keys via the resolver's logger and
return a descriptive error from the resolver method (or alternatively skip/omit
missing entries if intended), ensuring you reference componenthelper.Component,
keys, byKey and the function that builds/returns ordered to locate the change.
- Around line 123-125: The purl-type filter currently only skips when both
purlType and u.PurlType are non-empty and unequal, allowing entries with empty
u.PurlType to pass when a purlType is specified; change the logic so any time
the incoming purlType parameter is non-empty and u.PurlType does not equal it
(including when u.PurlType is empty) the entry is skipped—update the conditional
that references purlType and u.PurlType in component_resolver.go (the place
where u.PurlType is compared to purlType) to use a single check: if purlType !=
"" && u.PurlType != purlType { continue } so empty u.PurlType values are
excluded when filtering by a specific purlType.
- Line 114: In filterUrlsInRange: broaden the wildcard check and tighten
purlType filtering — replace the requirement check that uses
strings.HasPrefix(requirement, "v*") with a test that treats any presence of a
v-style wildcard or an operator-prefixed wildcard as a skip (e.g.,
strings.Contains(requirement, "v*") and also trim and check for operator+v*
patterns) so semver expressions like ">=v*" or ">v*" are rejected too; and
change the purlType filter from "if purlType != "" && u.PurlType != "" &&
u.PurlType != purlType" to require a non-empty match (e.g., when purlType != ""
only keep URLs where u.PurlType != "" && u.PurlType == purlType) so entries with
empty u.PurlType are excluded when a purlType filter is supplied.

In `@pkg/usecase/cryptography_major.go`:
- Around line 97-101: The DB/query error handling in the block calling
d.allUrls.GetUrlsByPurlList (and the similar block around lines 125-131)
currently logs the error then converts it into a domain "not found/no info"
status by setting c.Status to status.ComponentNotFound/NoInfo; instead, preserve
and propagate the underlying storage error (or translate it to a distinct
backend-failure status) rather than treating it as business data. Update the
error handling in the GetUrlsByPurlList call (and the analogous query at
125-131) to return the error up the stack (or set c.Status to a dedicated
backend-failure status) after logging via s.Debugf, and only set
ComponentNotFound/NoInfo when you have confirmed the data truly does not exist
(e.g., zero results with no query error).

In `@pkg/usecase/cryptography_search.go`:
- Line 125: The function declaration for applySourceFallback exceeds the
line-length linter; break the long signature into multiple lines to satisfy lll
by wrapping parameters, e.g., place the receiver and function name on one line
and put parameters (ctx context.Context, s *zap.SugaredLogger, output
*domain.CryptoOutput, metadata []ComponentCryptoMetadata, components
[]dtos.ComponentDTO) each or grouped across subsequent lines; update the
signature in the applySourceFallback method accordingly so the line length is
under the linter limit.

In `@pkg/usecase/cryptography_versions_using.go`:
- Around line 95-98: The code in GetVersionsInRangeUsingCrypto currently
swallows backend/model/DB errors by setting item.Status to
status.ComponentNotFound or status.ComponentWithoutInfo (via assignments like
item.Status = status.ComponentStatus{StatusCode: status.ComponentNotFound, ...})
and returning; instead, either return the original error from
GetVersionsInRangeUsingCrypto (bubble it up) or set a dedicated internal-failure
status (e.g., status.ComponentInternalError) so real failures are
distinguishable from business "not found" results—replace the current
error-to-ComponentNotFound/ComponentWithoutInfo mappings around the error
handling blocks (where s.Debugf logs the error and item.Status is set) with code
that either returns the error to the caller or assigns a specific internal
failure ComponentStatus while preserving the original error message for logging.
- Around line 94-112: The code currently fetches URLs via
d.allUrls.GetUrlsByPurlList using purlName only and then treats an empty
post-filter result as VersionNotFound; change this so you distinguish "component
not found for this ecosystem" from "no version matches": either query
GetUrlsByPurlList with both purlName and purlType (if supported) or immediately
filter the returned urls by purl.Type == purlType (using the variable purlType)
before calling filterUrlsInRange; after this type-filter, if
len(typeFilteredUrls) == 0 set item.Status to status.ComponentNotFound (using
status.ComponentNotFound and the same message format), otherwise call
filterUrlsInRange(typeFilteredUrls, purlType, item.Requirement) and keep the
existing handling that sets status.VersionNotFound when the result is empty.

In `@pkg/usecase/library_detections.go`:
- Line 251: GetUrlsByPurlList + filterUrlsInRange can return mixed-type rows
because utils.PurlReq has no type and filterUrlsInRange only rejects mismatches
when both sides are non-empty; update the logic so callers can avoid cross-type
collisions: either extend utils.PurlReq to include a PurlType and have
allUrls.GetUrlsByPurlList filter by m.purl_type when PurlType is provided, or
(simpler) change filterUrlsInRange to also reject rows where a requested
purlType is non-empty but the returned u.PurlType is empty (i.e., discard rows
with empty u.PurlType when purlType != ""), referencing utils.PurlReq,
allUrls.GetUrlsByPurlList and filterUrlsInRange to locate where to implement the
change.
- Around line 53-66: The loop indexing is fine, but you must normalize any
"file:" prefixed requirement before passing it to range filtering to avoid
semver.NewConstraint treating it as invalid; in GetDetectionsInRange/where you
call processSinglePurl and ultimately filterUrlsInRange, strip the "file:"
prefix (or use the resolved item's c.OriginalRequirement/normalized requirement)
so filterUrlsInRange receives a plain semver requirement (or empty string to
mean "latest"), ensuring semver.NewConstraint won't return status.InvalidSemver;
update calls that use components[i].Requirement to use the normalized
requirement from resolveComponentVersions (or c.OriginalRequirement) instead.

---

Outside diff comments:
In `@pkg/usecase/cryptography_search.go`:
- Around line 45-54: ComponentCryptoMetadata currently loses the resolved purl
type which lets same-name packages across ecosystems share SelectedURLS and
produce incorrect crypto hits; add a PurlType field to ComponentCryptoMetadata
to preserve the resolved type, populate it wherever metadata is created, and
update the URL selection logic that builds urlHashes (the code that filters
SelectedURLS/models.AllURL) to filter by both PurlType and exact Version before
constructing urlHashes; also apply the same change in the other two places noted
(the other URL-selection blocks that use SelectedURLS and build urlHashes).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f4d3f225-060e-47ea-ae07-18b6ceaf02a0

📥 Commits

Reviewing files that changed from the base of the PR and between 926c170 and 83fea62.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (19)
  • go.mod
  • pkg/handlers/cryptography_support.go
  • pkg/models/all_urls.go
  • pkg/models/all_urls_test.go
  • pkg/models/common.go
  • pkg/models/doc.go
  • pkg/models/tests/licenses.sql
  • pkg/responsebuilder/test.json
  • pkg/usecase/component_resolver.go
  • pkg/usecase/component_resolver_test.go
  • pkg/usecase/component_validator.go
  • pkg/usecase/cryptography_major.go
  • pkg/usecase/cryptography_search.go
  • pkg/usecase/cryptography_versions_using.go
  • pkg/usecase/docs.go
  • pkg/usecase/library_detections.go
  • pkg/utils/doc.go
  • pkg/utils/semver.go
  • pkg/utils/semver_test.go
💤 Files with no reviewable changes (8)
  • pkg/utils/semver_test.go
  • pkg/utils/semver.go
  • pkg/usecase/component_validator.go
  • pkg/handlers/cryptography_support.go
  • pkg/models/doc.go
  • pkg/models/all_urls.go
  • pkg/utils/doc.go
  • pkg/models/all_urls_test.go

Comment thread pkg/usecase/component_resolver_test.go
Comment thread pkg/usecase/component_resolver.go
Comment thread pkg/usecase/component_resolver.go
Comment thread pkg/usecase/component_resolver.go Outdated
Comment thread pkg/usecase/component_resolver.go Outdated
Comment thread pkg/usecase/cryptography_search.go Outdated
Comment thread pkg/usecase/cryptography_versions_using.go
Comment thread pkg/usecase/cryptography_versions_using.go
Comment thread pkg/usecase/library_detections.go
Comment thread pkg/usecase/library_detections.go

@agustingroh agustingroh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@scanoss-qg scanoss-qg merged commit a0c32b2 into main Jun 2, 2026
3 checks passed
@scanoss-qg scanoss-qg deleted the SP4351-SourcePurlInfo branch June 2, 2026 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants