mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
Added parser for Pipfile.lock to cataloger (#473)
* Added parser for Pipfile.lock to cataloger Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com> * make lint-fix Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com> * Update syft/pkg/cataloger/python/parse_pipfile_lock.go Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com> Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com> * fix _version Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com> * swap method for trimming "==" prefix from pipfile pkg versions Signed-off-by: Alex Goodman <alex.goodman@anchore.com> Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com> Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
b0e9b92a25
commit
cba5b5723b
@ -12,6 +12,7 @@ func NewPythonIndexCataloger() *common.GenericCataloger {
|
|||||||
globParsers := map[string]common.ParserFn{
|
globParsers := map[string]common.ParserFn{
|
||||||
"**/*requirements*.txt": parseRequirementsTxt,
|
"**/*requirements*.txt": parseRequirementsTxt,
|
||||||
"**/poetry.lock": parsePoetryLock,
|
"**/poetry.lock": parsePoetryLock,
|
||||||
|
"**/Pipfile.lock": parsePipfileLock,
|
||||||
"**/setup.py": parseSetup,
|
"**/setup.py": parseSetup,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
63
syft/pkg/cataloger/python/parse_pipfile_lock.go
Normal file
63
syft/pkg/cataloger/python/parse_pipfile_lock.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package python
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PipfileLock struct {
|
||||||
|
Meta struct {
|
||||||
|
Hash struct {
|
||||||
|
Sha256 string `json:"sha256"`
|
||||||
|
} `json:"hash"`
|
||||||
|
PipfileSpec int `json:"pipfile-spec"`
|
||||||
|
Requires struct {
|
||||||
|
PythonVersion string `json:"python_version"`
|
||||||
|
} `json:"requires"`
|
||||||
|
Sources []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
VerifySsl bool `json:"verify_ssl"`
|
||||||
|
} `json:"sources"`
|
||||||
|
} `json:"_meta"`
|
||||||
|
Default map[string]Dependency `json:"default"`
|
||||||
|
Develop map[string]Dependency `json:"develop"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dependency struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// integrity check
|
||||||
|
var _ common.ParserFn = parsePipfileLock
|
||||||
|
|
||||||
|
// parsePipfileLock is a parser function for Pipfile.lock contents, returning "Default" python packages discovered.
|
||||||
|
func parsePipfileLock(_ string, reader io.Reader) ([]pkg.Package, error) {
|
||||||
|
packages := make([]pkg.Package, 0)
|
||||||
|
dec := json.NewDecoder(reader)
|
||||||
|
|
||||||
|
for {
|
||||||
|
var lock PipfileLock
|
||||||
|
if err := dec.Decode(&lock); err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse Pipfile.lock file: %w", err)
|
||||||
|
}
|
||||||
|
for name, pkgMeta := range lock.Default {
|
||||||
|
version := strings.TrimPrefix(pkgMeta.Version, "==")
|
||||||
|
packages = append(packages, pkg.Package{
|
||||||
|
Name: name,
|
||||||
|
Version: version,
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return packages, nil
|
||||||
|
}
|
||||||
49
syft/pkg/cataloger/python/parse_pipfile_lock_test.go
Normal file
49
syft/pkg/cataloger/python/parse_pipfile_lock_test.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package python
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParsePipFileLock(t *testing.T) {
|
||||||
|
expected := map[string]pkg.Package{
|
||||||
|
"aio-pika": {
|
||||||
|
Name: "aio-pika",
|
||||||
|
Version: "6.8.0",
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
},
|
||||||
|
"aiodns": {
|
||||||
|
Name: "aiodns",
|
||||||
|
Version: "2.0.0",
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
},
|
||||||
|
"aiohttp": {
|
||||||
|
Name: "aiohttp",
|
||||||
|
Version: "3.7.4.post0",
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
},
|
||||||
|
"aiohttp-jinja2": {
|
||||||
|
Name: "aiohttp-jinja2",
|
||||||
|
Version: "1.4.2",
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.PythonPkg,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
fixture, err := os.Open("test-fixtures/pipfile-lock/Pipfile.lock")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := parsePipfileLock(fixture.Name(), fixture)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to parse requirements: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertPackagesEqual(t, actual, expected)
|
||||||
|
|
||||||
|
}
|
||||||
69
syft/pkg/cataloger/python/test-fixtures/pipfile-lock/Pipfile.lock
generated
Normal file
69
syft/pkg/cataloger/python/test-fixtures/pipfile-lock/Pipfile.lock
generated
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "a6b2dfd5367688bec81240eb04e7bde7f92b35491be5934fcb4e2e6ca9d275c0"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.8"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"aio-pika": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1d4305a5f78af3857310b4fe48348cdcf6c097e0e275ea88c2cd08570531a369",
|
||||||
|
"sha256:e69afef8695f47c5d107bbdba21bdb845d5c249acb3be53ef5c2d497b02657c0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==6.8.0"
|
||||||
|
},
|
||||||
|
"aiodns": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:815fdef4607474295d68da46978a54481dd1e7be153c7d60f9e72773cd38d77d",
|
||||||
|
"sha256:aaa5ac584f40fe778013df0aa6544bf157799bd3f608364b451840ed2c8688de"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.0.0"
|
||||||
|
},
|
||||||
|
"aiohttp": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe",
|
||||||
|
"sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.7.4.post0"
|
||||||
|
},
|
||||||
|
"aiohttp-jinja2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:860da7582efa866744bad5883947557d0f82e457d69903ea65d666b66f8a69ca",
|
||||||
|
"sha256:9c22a0e48e3b277fc145c67dd8c3b8f609dab36bce9eb337f70dfe716663c9a0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {
|
||||||
|
"astroid": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6b0ed1af831570e500e2437625979eaa3b36011f66ddfc4ce930128610258ca9",
|
||||||
|
"sha256:cd80bf957c49765dce6d92c43163ff9d2abc43132ce64d4b1b47717c6d2522df"
|
||||||
|
],
|
||||||
|
"version": "==2.5.2"
|
||||||
|
},
|
||||||
|
"autopep8": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5454e6e9a3d02aae38f866eec0d9a7de4ab9f93c10a273fb0340f3d6d09f7514",
|
||||||
|
"sha256:f01b06a6808bc31698db907761e5890eb2295e287af53f6693b39ce55454034a"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.5.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user