Skip to content

Conversation

@academo
Copy link
Collaborator

@academo academo commented Oct 20, 2025

Fixes: #418

The logic of the filtering remains the same but it is now expanded to find all transitive dependencies of all versions of a package inside the grafana dependencies list

e.g.
@grafana/data@v1 brings dependencies: a, b, and c
@grafana/data@v2 brings dependencies: a, e, and f

in the old version we'd only report a, b, and c as transitive dependencies of @grafana/data with this changes we'll report: a, b, c, e and f

@academo academo self-assigned this Oct 20, 2025
@academo academo moved this from 📬 Triage to 🔬 In review in Plugins Platform / Grafana Community Oct 20, 2025
@academo academo marked this pull request as ready for review October 20, 2025 11:28
@academo academo requested review from a team as code owners October 20, 2025 11:28
@academo academo requested a review from xnyo October 20, 2025 11:36
@academo academo force-pushed the academo/fix-osv-scanner-multi-version-dependency branch from b11b4e0 to ca6ab91 Compare October 20, 2025 11:37
Copy link
Contributor

@andresmgot andresmgot left a comment

Choose a reason for hiding this comment

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

Some comments about the maintainabilty of this code, feel free to ignore it since it's covered by tests.

Comment on lines +29 to +43
for _, pkg := range allPackages {
if GrafanaPackages[pkg.Name] && !processedNames[pkg.Name] {
processedNames[pkg.Name] = true

allVersions := make([]lockfile.PackageDetails, 0)
for _, p := range allPackages {
if p.Name == pkg.Name {
allVersions = append(allVersions, p)
}
}

// should never happen
if len(allVersions) == 0 {
continue
}
Copy link
Contributor

Choose a reason for hiding this comment

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

probably we don't need to worry about performance here but better code would be: rather than iterating twice over allPackages, would be to create a map packagesToProcess[string]struct{Name,Versions} and then you iterate over that map to process them

Comment on lines +80 to +115
func expandDependenciesRecursively(
topLevel *lockfile.PackageFlattened,
allPackages []lockfile.PackageDetails,
) {
for i := 0; i < len(topLevel.Dependencies); i++ {
if topLevel.Dependencies[i].Processed {
continue
}

topLevel.Dependencies[i].Processed = true
depName := topLevel.Dependencies[i].Package.Name

var depPackage *lockfile.PackageDetails
for j := range allPackages {
if allPackages[j].Name == depName {
depPackage = &allPackages[j]
break
}
}

if depPackage == nil {
continue
}

for _, subDep := range depPackage.Dependencies {
// do not add them twice
if !dependencyExists(subDep.Name, topLevel.Dependencies) {
state := lockfile.DependencyState{
Package: subDep,
Processed: false,
}
topLevel.Dependencies = append(topLevel.Dependencies, state)
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

honestly, this function is really hard to read or understand (I tried for several minutes and failed 😅 ). It's mixing npm variable names (dep, package, lockfile), with iterative vars (i, j), modifying the input (topLevel) in several places, breaking the loop in other places... I don't have a suggestion because I don't know what this is doing but I'd try to make it more modular, with more comments and avoid modifying inputs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I know! this code is absurdly complex but, it is harder to make it more readable because the structure of lock files is deep and recursive so one have to create code like this.

I will add more comments to the code so it is easier to follow up

Copy link
Contributor

Choose a reason for hiding this comment

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

do you really need a 25k file for this? It's impossible to know which parts are important, I would rather see a fake file with only the nested cases you are interested in testing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

likely not, but it is a real lock file from a real plugin that presented this issue.

the problem is that lock files tend to be huge because they are not meant to read manually and the dependency I found that had issues has hundreds of transitive dependencies that inflate this file.

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, my point is that for this to be readable the input of a test needs to be readable. Right now is: I give you this obscure blob and you have to trust me that the expected output is that it founds dompurify in this specific format. In the other hand, if this file is 10 lines long, I'm able to see where dompurify is and how the test is processing it.

Also, if I need to add something else to the logic and test it with something this file doesn't have, I wouldn't be able to modify this package-lock.json because I don't know which parts are important, so I'd need to add multi-version-npm-2, with another 25k lines of code and again that file becomes immutable for the next person.

This is just a general comment, I'm not a fan of test files representing real stuff vs minimal (fake) input that easily represents what the test is meant to cover.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I removed most of the bulk and left it to the bare minimum but it is still far from "readable" it just now contains the minimum necessary to trigger the issues we try to test

@academo academo merged commit e12fba3 into main Oct 24, 2025
6 checks passed
@academo academo deleted the academo/fix-osv-scanner-multi-version-dependency branch October 24, 2025 13:24
@github-project-automation github-project-automation bot moved this from 🔬 In review to 🚀 Shipped in Plugins Platform / Grafana Community Oct 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🚀 Shipped

Development

Successfully merging this pull request may close these issues.

OSV Scanner: Vulnerabilities in Grafana Dependencies Not Filtered When Multiple Versions Present

2 participants