Support for scanning manifest files (#36)

* feat: add extractor logic for manifest files

* feat: add manifest-based package installation detection

* feat: add osv-scanner for extracting lockfiles

* refactor: add comment for cmd parse

* refactor: add Ecosystem() method to PackageManager interface

* refactor: implement package-manager-specific extractors & replace osv-scanner with scalibr

* Update extractor/extractor.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Sahil Bansal
2025-06-12 18:58:58 +05:30
committed by GitHub
co-authored by Copilot
parent 302e17fe48
commit 5e9f2af972
13 changed files with 690 additions and 16 deletions
+68
View File
@@ -0,0 +1,68 @@
package extractor
import (
"context"
"fmt"
"os"
packagev1 "buf.build/gen/go/safedep/api/protocolbuffers/go/safedep/messages/package/v1"
"github.com/google/osv-scalibr/extractor/filesystem"
"github.com/google/osv-scalibr/extractor/filesystem/language/python/requirements"
"github.com/google/osv-scalibr/fs"
)
// PipExtractor handles requirements.txt files
type PipExtractor struct{}
func (p *PipExtractor) GetSupportedFiles() []string {
return []string{"requirements.txt"}
}
func (p *PipExtractor) GetEcosystem() packagev1.Ecosystem {
return packagev1.Ecosystem_ECOSYSTEM_PYPI
}
func (p *PipExtractor) GetPackageManager() PackageManagerName {
return Pip
}
func (n *PipExtractor) Extract(lockfilePath, scanDir string) ([]*packagev1.PackageVersion, error) {
return parseRequirementsTxtFile(lockfilePath, scanDir)
}
func parseRequirementsTxtFile(lockfilePath, scanDir string) ([]*packagev1.PackageVersion, error) {
requirementsExtractor := requirements.NewDefault()
file, err := os.Open(lockfilePath)
if err != nil {
return nil, fmt.Errorf("failed to open lockfile: %s", err)
}
defer file.Close()
inputConfig := &filesystem.ScanInput{
FS: fs.DirFS(scanDir),
Path: lockfilePath,
Reader: file,
}
inventory, err := requirementsExtractor.Extract(context.Background(), inputConfig)
if err != nil {
return nil, fmt.Errorf("failed to extract packages: %s", err)
}
var packages []*packagev1.PackageVersion
for _, invPkg := range inventory.Packages {
pkg := &packagev1.PackageVersion{
Package: &packagev1.Package{
Name: invPkg.Name,
Ecosystem: packagev1.Ecosystem_ECOSYSTEM_PYPI,
},
Version: invPkg.Version,
}
packages = append(packages, pkg)
}
return packages, nil
}