77 "encoding/json"
88 "fmt"
99 "log"
10+ "net/url"
1011 "os"
1112 "path/filepath"
1213 "runtime"
@@ -131,6 +132,11 @@ func (s *OpenSSFScanner) checkPackage(pkg ftypes.Package, target string, toolExe
131132 pkgType := s .getPackageType (pkg )
132133 pkgNameLower := strings .ToLower (pkg .Name )
133134
135+ // If we can't determine package type from PURL, try to infer it from the target file
136+ if pkgType == "" {
137+ pkgType = s .inferPackageTypeFromTarget (target )
138+ }
139+
134140 candidates := s .lookup (pkgType , pkgNameLower )
135141 if len (candidates ) == 0 {
136142 return nil
@@ -144,6 +150,32 @@ func (s *OpenSSFScanner) checkPackage(pkg ftypes.Package, target string, toolExe
144150 return nil
145151}
146152
153+ // inferPackageTypeFromTarget tries to infer the package type from the target file path
154+ func (s * OpenSSFScanner ) inferPackageTypeFromTarget (target string ) string {
155+ switch {
156+ case strings .HasSuffix (target , "package.json" ):
157+ return "npm"
158+ case strings .HasSuffix (target , "package-lock.json" ):
159+ return "npm"
160+ case strings .HasSuffix (target , "yarn.lock" ):
161+ return "npm"
162+ case strings .HasSuffix (target , "go.mod" ):
163+ return "golang"
164+ case strings .HasSuffix (target , "requirements.txt" ):
165+ return "pypi"
166+ case strings .HasSuffix (target , "Pipfile" ):
167+ return "pypi"
168+ case strings .HasSuffix (target , "poetry.lock" ):
169+ return "pypi"
170+ case strings .HasSuffix (target , "pom.xml" ):
171+ return "maven"
172+ case strings .HasSuffix (target , "build.gradle" ):
173+ return "gradle"
174+ default :
175+ return ""
176+ }
177+ }
178+
147179// getPackageType extracts the package type from PURL
148180func (s * OpenSSFScanner ) getPackageType (pkg ftypes.Package ) string {
149181 if pkg .Identifier .PURL != nil {
@@ -152,6 +184,20 @@ func (s *OpenSSFScanner) getPackageType(pkg ftypes.Package) string {
152184 return ""
153185}
154186
187+ // getPackageDisplayName returns a display name for the package, handling nil PURLs
188+ func (s * OpenSSFScanner ) getPackageDisplayName (pkg ftypes.Package ) string {
189+ if pkg .Identifier .PURL != nil {
190+ // Use the same logic as the main tool for consistency
191+ purlStripPkg := strings .TrimPrefix (pkg .Identifier .PURL .ToString (), "pkg:" )
192+ if ppp , err := url .PathUnescape (purlStripPkg ); err == nil {
193+ return ppp
194+ }
195+ return purlStripPkg
196+ }
197+ // Fallback to package name when PURL is not available
198+ return pkg .Name
199+ }
200+
155201// createIssue creates a malicious package issue
156202func (s * OpenSSFScanner ) createIssue (pkg ftypes.Package , target string , cand osvShallow , toolExecution codacy.ToolExecution ) []codacy.Result {
157203 lineNumber := s .findPackageLineNumber (toolExecution .SourceDir , target , pkg .Name )
@@ -197,7 +243,7 @@ func (s *OpenSSFScanner) scanNpmManifest(sourceDir, relativePath string, knownFi
197243 return nil
198244 }
199245
200- return s .checkNpmDependencies (pj .Dependencies , relativePath )
246+ return s .checkNpmDependencies (pj .Dependencies , sourceDir , relativePath )
201247}
202248
203249// parseNpmPackage parses an npm package.json file
@@ -216,18 +262,18 @@ func (s *OpenSSFScanner) parseNpmPackage(sourceDir, relativePath string) (*npmPk
216262}
217263
218264// checkNpmDependencies checks npm dependencies for malicious packages
219- func (s * OpenSSFScanner ) checkNpmDependencies (dependencies map [string ]string , relativePath string ) []codacy.Result {
265+ func (s * OpenSSFScanner ) checkNpmDependencies (dependencies map [string ]string , sourceDir , relativePath string ) []codacy.Result {
220266 var out []codacy.Result
221267 for name , ver := range dependencies {
222- if issue := s .checkNpmDependency (name , ver , relativePath ); issue != nil {
268+ if issue := s .checkNpmDependency (name , ver , sourceDir , relativePath ); issue != nil {
223269 out = append (out , * issue )
224270 }
225271 }
226272 return out
227273}
228274
229275// checkNpmDependency checks a single npm dependency
230- func (s * OpenSSFScanner ) checkNpmDependency (name , ver , relativePath string ) * codacy.Issue {
276+ func (s * OpenSSFScanner ) checkNpmDependency (name , ver , sourceDir , relativePath string ) * codacy.Issue {
231277 pkgNameLower := strings .ToLower (name )
232278 candidates := s .lookup ("npm" , pkgNameLower )
233279 if len (candidates ) == 0 {
@@ -236,10 +282,11 @@ func (s *OpenSSFScanner) checkNpmDependency(name, ver, relativePath string) *cod
236282
237283 for _ , cand := range candidates {
238284 if s .versionMatches (ver , cand .Versions , cand .Ranges ) {
285+ lineNumber := s .findPackageLineNumber (sourceDir , relativePath , name )
239286 issue := codacy.Issue {
240287 File : relativePath ,
241288 Message : fmt .Sprintf ("Malicious package detected: %s@%s - %s" , name , ver , cand .Summary ),
242- Line : 1 ,
289+ Line : lineNumber ,
243290 PatternID : ruleIDMaliciousPackages ,
244291 SourceID : cand .ID ,
245292 }
0 commit comments