Skip to content

feat(sbom): resolve version unknown#58

Open
reyreavman wants to merge 8 commits intomainfrom
feat/sbom/resolve-version-unknown
Open

feat(sbom): resolve version unknown#58
reyreavman wants to merge 8 commits intomainfrom
feat/sbom/resolve-version-unknown

Conversation

@reyreavman
Copy link
Collaborator

No description provided.

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
@reyreavman reyreavman force-pushed the feat/sbom/resolve-version-unknown branch from 2c9fb85 to c53c4c8 Compare March 6, 2026 09:24
- Move _fixtures/sbom-go-replace/state0 → _fixtures/sbom/go_replace
- Add git tag v1.0.0 in test setup for deterministic version
- Assert exact version v1.0.0 instead of just not-UNKNOWN

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
Local.TagCommit was missing — only Remote had an implementation.
The Base panic stub was being called at runtime when resolving
Go module versions from git tags.

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
Syft writes "(devel)" (not "UNKNOWN") for local replace modules, and
uses the filesystem path (e.g. "./mylib") as component name instead of
the module name. Fix both:
- Match (devel) in addition to UNKNOWN
- Include local replace paths (New.Path) in match targets
- Handle URL-encoded %28devel%29 in PURL

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
…2e test

Syft records local replace modules with filesystem path (./mylib)
as component name, not the module name (example.com/mylib).

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
When Syft records a local replace module with filesystem path as name
(e.g. ./mylib), replace it with the actual module name from go.mod
replace directive (e.g. example.com/mylib) and rebuild PURL accordingly.

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
…ocessing

Replace gitRepo/commit/imageContext params in ConvergeWithMerge with
[]BOMPatcher — a slice of transform functions. Each patcher is a
closure built by the caller. Adding a new patcher requires only
appending a new function to the slice, no signature changes.

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
@reyreavman reyreavman force-pushed the feat/sbom/resolve-version-unknown branch from ab4ff73 to 7a90b88 Compare March 10, 2026 09:31
…ent patcher

PatchComponents(bom, match, patch) iterates BOM components and applies
a transformation to each matching one. ResolveUnknownGoVersions is now
built on top of it. New patchers can reuse the same traversal.

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
cdx "github.com/CycloneDX/cyclonedx-go"
)

func PatchComponents(bom *cdx.BOM, match func(*cdx.Component) bool, patch func(*cdx.Component)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the function should be immutable and it should return a new patched copy of BOM. Let's discuss it.

}

var patchers []BOMPatcher
gomodPatcher := func(ctx context.Context, bom *cdx.BOM) (*cdx.BOM, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's improve code readability and test-ability.

I suggest :

  • Introduce NewBOMPacther(ctx, bom, gitRepo, commit, imageCtx) constructor which returns type BOMPatcher which implement interface ... BOMPatcherInterface
  • Let's assume BOMPatcher has method Apply(ctx).
  • Let's assume phase.sbomStep.ConvergeWithMerge(ctx, name, stageDesc, scanner.DefaultSyftScanOptions(), mergeOpts, patcher /* BOMPatcherInterface */)


ctx = logging.WithLogger(ctx)
var patchers []BOMPatcher
if setupGitRepo != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should be able to mock it. For example, using BOMPatcherInterface


result, err := ResolveUnknownVersions(ctx, bom, gitRepo, commit, imageContext)

if expectError {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's keep in simple (in one line): expect Succeed() or MatchError(ContainSubstring(expectedErrorMsg))


// ResolveVersionFromTags finds a semver tag matching the given commit.
// Falls back to pseudo-version v0.0.0-{shortCommit} if no tag matches.
func ResolveVersionFromTags(tags []string, commitForTag func(tag string) (string, error), commit string) (string, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why don't we use

github.com/Masterminds/semver v1.5.0
for working with semver?

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