X Tutup
Skip to content

feat: begin implementing ecosystem helpers in Go#4926

Open
michaelkedar wants to merge 2 commits intogoogle:masterfrom
michaelkedar:🏜️🏞️

Hidden character warning

The head ref may contain hidden characters: "\ud83c\udfdc\ufe0f\ud83c\udfde\ufe0f"
Open

feat: begin implementing ecosystem helpers in Go#4926
michaelkedar wants to merge 2 commits intogoogle:masterfrom
michaelkedar:🏜️🏞️

Conversation

@michaelkedar
Copy link
Member

Setting up the groundwork for re-implementing the python ecosystems stuff (so we can migrate the worker and API)

Right now, this is just the version comparison stuff, without coarse versions and enumeration. It also just directly delegates to the osv-scalibr (née osv-scanner) implementation of them.
The only interesting one is Root, which is not (currently?) covered by the semantic package.

I don't know if I should be porting the python tests over for comparison logic - this stuff should already be tested in scalibr, and I'm barely adding extra logic on top (and the extra logic of "0" handling I have added tests for)

@michaelkedar
Copy link
Member Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request lays the groundwork for ecosystem helpers in Go by re-implementing version comparison logic, delegating to osv-scalibr. It introduces many new files for different ecosystems and a wrapper to handle special version "0" cases. The overall structure is solid. I've found a critical issue in the root ecosystem version parsing logic that could lead to incorrect version comparisons, and a recurring issue where unimplemented methods panic instead of returning an error. My detailed comments provide suggestions for fixes.

Comment on lines +94 to +115
if m := rootIOPlusRegexp.FindStringSubmatch(version); m != nil {
upstreamVersion = m[1]
rootPatch, err = strconv.Atoi(m[2])
if err != nil {
return nil, err
}
}
// Generic Format
if m := rootIOGenericRegexp.FindStringSubmatch(version); m != nil {
upstreamVersion = m[1]
rootPatch, err = strconv.Atoi(m[2])
if err != nil {
return nil, err
}
}
// Alpine Format
if m := rootAlpineRegexp.FindStringSubmatch(upstreamVersion); m != nil {
rootPatch, err = strconv.Atoi(m[2])
if err != nil {
return nil, err
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The version parsing logic for the Root ecosystem has a few issues that could lead to incorrect behavior:

  1. Lack of mutual exclusion: The root.io suffix parsers (rootIOPlusRegexp and rootIOGenericRegexp) are not in an if-else if chain, meaning if a version string could match both, the second would overwrite the first.
  2. Patch overwrite: The rootAlpineRegexp match overwrites any rootPatch value found from root.io suffixes. This is likely a bug, as a version like 1.2.3-r4+root.io.5 would lose the root.io patch information.
  3. Incomplete version stripping: The rootAlpineRegexp does not strip the matched suffix (e.g., -r4) from upstreamVersion. This will cause parsing errors in sub-ecosystem parsers that don't expect this format, such as dpkgEcosystem.

I suggest chaining the regex checks with else if to establish precedence and fix the overwrite issue, and ensuring the suffix is stripped in all cases.

	if m := rootIOPlusRegexp.FindStringSubmatch(version); m != nil {
		upstreamVersion = m[1]
		rootPatch, err = strconv.Atoi(m[2])
		if err != nil {
			return nil, err
		}
	} else if m := rootIOGenericRegexp.FindStringSubmatch(version); m != nil {
		upstreamVersion = m[1]
		rootPatch, err = strconv.Atoi(m[2])
		if err != nil {
			return nil, err
		}
	} else if m := rootAlpineRegexp.FindStringSubmatch(version); m != nil {
		upstreamVersion = m[1]
		rootPatch, err = strconv.Atoi(m[2])
		if err != nil {
			return nil, err
		}
	}

Copy link
Member Author

Choose a reason for hiding this comment

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

This is exactly what the python implementation was doing:

# Extract Root-specific suffixes
# Python format: <version>+root.io.<number>
python_match = re.match(r'^(.+?)\+root\.io\.(\d+)$', version)
if python_match:
upstream_version = python_match.group(1)
root_patch = int(python_match.group(2))
# Generic format: <version>.root.io.<number>
other_match = re.match(r'^(.+?)\.root\.io\.(\d+)$', version)
if other_match:
upstream_version = other_match.group(1)
root_patch = int(other_match.group(2))
# Alpine format with Root suffix: <version>-r<number>
# Note: Alpine naturally uses -r<revision>
alpine_match = re.match(r'^(.+?)-r(\d+)$', upstream_version)
if alpine_match:
root_patch = int(alpine_match.group(2))

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add a TODO here to keep track of it? Having "if else" probably is a good idea.

Comment on lines +23 to +25
func (e bioconductorEcosystem) GetVersions(_ string) ([]string, error) {
panic("not yet implemented")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Using panic for unimplemented functions can cause the entire application to crash, which is not ideal for library code. It's better to return an error, for example errors.New("not yet implemented"). You will need to add import "errors" to the file.

This comment applies to all other GetVersions methods in this pull request that currently use panic.

Suggested change
func (e bioconductorEcosystem) GetVersions(_ string) ([]string, error) {
panic("not yet implemented")
}
func (e bioconductorEcosystem) GetVersions(_ string) ([]string, error) {
return nil, errors.New("not yet implemented")
}

Copy link
Member Author

Choose a reason for hiding this comment

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

This aren't going to be used before these are implemented.

another-rex
another-rex previously approved these changes Mar 6, 2026
Copy link
Contributor

@another-rex another-rex left a comment

Choose a reason for hiding this comment

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

Looks great to me

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

X Tutup