feat: add BeamVM Hex support (#1073)

* feat: initial commit providing mix support

Signed-off-by: cpendery <cpendery@vt.edu>

* feat: add rebar parser

Signed-off-by: cpendery <cpendery@vt.edu>

* fix: add beam/hex everywhere else required for Syft runtime

Signed-off-by: cpendery <cpendery@vt.edu>

* style: fix lints

Signed-off-by: cpendery <cpendery@vt.edu>

* ci: fix failing tests

Signed-off-by: cpendery <cpendery@vt.edu>

* docs: update with new supported languages

Signed-off-by: cpendery <cpendery@vt.edu>

* chore: update elixir/erlang catalogers to generic cataloger

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: cpendery <cpendery@vt.edu>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Chapman Pendery
2023-01-12 12:10:46 -05:00
committed by GitHub
co-authored by Alex Goodman
parent e063471c66
commit ac8f72fdd1
27 changed files with 914 additions and 133 deletions
+16
View File
@@ -0,0 +1,16 @@
/*
Package erlang provides a concrete Cataloger implementation for erlang specific package manger files.
*/
package erlang
import (
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)
const catalogerName = "erlang-rebar-lock-cataloger"
// NewRebarLockCataloger returns parses rebar.lock files and returns packages.
func NewRebarLockCataloger() *generic.Cataloger {
return generic.NewCataloger(catalogerName).
WithParserByGlobs(parseRebarLock, "**/rebar.lock")
}
+37
View File
@@ -0,0 +1,37 @@
package erlang
import (
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
func newPackage(d pkg.RebarLockMetadata, locations ...source.Location) pkg.Package {
p := pkg.Package{
Name: d.Name,
Version: d.Version,
Language: pkg.Erlang,
Locations: source.NewLocationSet(locations...),
PURL: packageURL(d),
Type: pkg.HexPkg,
MetadataType: pkg.RebarLockMetadataType,
Metadata: d,
}
p.SetID()
return p
}
func packageURL(m pkg.RebarLockMetadata) string {
var qualifiers packageurl.Qualifiers
return packageurl.NewPackageURL(
packageurl.TypeHex,
"",
m.Name,
m.Version,
qualifiers,
"",
).ToString()
}
@@ -0,0 +1,80 @@
package erlang
import (
"bufio"
"errors"
"fmt"
"io"
"regexp"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
"github.com/anchore/syft/syft/source"
)
// integrity check
var _ generic.Parser = parseRebarLock
var rebarLockDelimiter = regexp.MustCompile(`[\[{<">},: \]\n]+`)
// parseMixLock parses a mix.lock and returns the discovered Elixir packages.
func parseRebarLock(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
r := bufio.NewReader(reader)
pkgMap := make(map[string]*pkg.Package)
var names []string
loop:
for {
line, err := r.ReadString('\n')
switch {
case errors.Is(io.EOF, err):
break loop
case err != nil:
// TODO: return partial result and warn
return nil, nil, fmt.Errorf("failed to parse rebar.lock file: %w", err)
}
tokens := rebarLockDelimiter.Split(line, -1)
if len(tokens) < 4 {
continue
}
if len(tokens) < 5 {
name, hash := tokens[1], tokens[2]
sourcePkg := pkgMap[name]
metadata := sourcePkg.Metadata.(pkg.RebarLockMetadata)
if metadata.PkgHash == "" {
metadata.PkgHash = hash
} else {
metadata.PkgHashExt = hash
}
sourcePkg.Metadata = metadata
continue
}
name, version := tokens[1], tokens[4]
sourcePkg := pkg.Package{
Name: name,
Version: version,
Language: pkg.Erlang,
Type: pkg.HexPkg,
MetadataType: pkg.RebarLockMetadataType,
}
p := newPackage(pkg.RebarLockMetadata{
Name: name,
Version: version,
})
names = append(names, name)
pkgMap[sourcePkg.Name] = &p
}
var packages []pkg.Package
for _, name := range names {
p := pkgMap[name]
p.SetID()
packages = append(packages, *p)
}
return packages, nil, nil
}
@@ -0,0 +1,119 @@
package erlang
import (
"testing"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
)
func TestParseRebarLock(t *testing.T) {
expected := []pkg.Package{
{
Name: "certifi",
Version: "2.9.0",
Language: pkg.Erlang,
Type: pkg.HexPkg,
PURL: "pkg:hex/certifi@2.9.0",
MetadataType: pkg.RebarLockMetadataType,
Metadata: pkg.RebarLockMetadata{
Name: "certifi",
Version: "2.9.0",
PkgHash: "6F2A475689DD47F19FB74334859D460A2DC4E3252A3324BD2111B8F0429E7E21",
PkgHashExt: "266DA46BDB06D6C6D35FDE799BCB28D36D985D424AD7C08B5BB48F5B5CDD4641",
},
},
{
Name: "idna",
Version: "6.1.1",
Language: pkg.Erlang,
Type: pkg.HexPkg,
PURL: "pkg:hex/idna@6.1.1",
MetadataType: pkg.RebarLockMetadataType,
Metadata: pkg.RebarLockMetadata{
Name: "idna",
Version: "6.1.1",
PkgHash: "8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D",
PkgHashExt: "92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA",
},
},
{
Name: "metrics",
Version: "1.0.1",
Language: pkg.Erlang,
Type: pkg.HexPkg,
PURL: "pkg:hex/metrics@1.0.1",
MetadataType: pkg.RebarLockMetadataType,
Metadata: pkg.RebarLockMetadata{
Name: "metrics",
Version: "1.0.1",
PkgHash: "25F094DEA2CDA98213CECC3AEFF09E940299D950904393B2A29D191C346A8486",
PkgHashExt: "69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16",
},
},
{
Name: "mimerl",
Version: "1.2.0",
Language: pkg.Erlang,
Type: pkg.HexPkg,
PURL: "pkg:hex/mimerl@1.2.0",
MetadataType: pkg.RebarLockMetadataType,
Metadata: pkg.RebarLockMetadata{
Name: "mimerl",
Version: "1.2.0",
PkgHash: "67E2D3F571088D5CFD3E550C383094B47159F3EEE8FFA08E64106CDF5E981BE3",
PkgHashExt: "F278585650AA581986264638EBF698F8BB19DF297F66AD91B18910DFC6E19323",
},
},
{
Name: "parse_trans",
Version: "3.3.1",
Language: pkg.Erlang,
Type: pkg.HexPkg,
PURL: "pkg:hex/parse_trans@3.3.1",
MetadataType: pkg.RebarLockMetadataType,
Metadata: pkg.RebarLockMetadata{
Name: "parse_trans",
Version: "3.3.1",
PkgHash: "16328AB840CC09919BD10DAB29E431DA3AF9E9E7E7E6F0089DD5A2D2820011D8",
PkgHashExt: "07CD9577885F56362D414E8C4C4E6BDF10D43A8767ABB92D24CBE8B24C54888B",
},
},
{
Name: "ssl_verify_fun",
Version: "1.1.6",
Language: pkg.Erlang,
Type: pkg.HexPkg,
PURL: "pkg:hex/ssl_verify_fun@1.1.6",
MetadataType: pkg.RebarLockMetadataType,
Metadata: pkg.RebarLockMetadata{
Name: "ssl_verify_fun",
Version: "1.1.6",
PkgHash: "CF344F5692C82D2CD7554F5EC8FD961548D4FD09E7D22F5B62482E5AEAEBD4B0",
PkgHashExt: "BDB0D2471F453C88FF3908E7686F86F9BE327D065CC1EC16FA4540197EA04680",
},
},
{
Name: "unicode_util_compat",
Version: "0.7.0",
Language: pkg.Erlang,
Type: pkg.HexPkg,
PURL: "pkg:hex/unicode_util_compat@0.7.0",
MetadataType: pkg.RebarLockMetadataType,
Metadata: pkg.RebarLockMetadata{
Name: "unicode_util_compat",
Version: "0.7.0",
PkgHash: "BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78",
PkgHashExt: "25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521",
},
},
}
fixture := "test-fixtures/rebar.lock"
// TODO: relationships are not under test
var expectedRelationships []artifact.Relationship
pkgtest.TestFileParser(t, fixture, parseRebarLock, expected, expectedRelationships)
}
@@ -0,0 +1,26 @@
{"1.2.0",
[{<<"certifi">>,{pkg,<<"certifi">>,<<"2.9.0">>},0},
{<<"idna">>,{pkg,<<"idna">>,<<"6.1.1">>},0},
{<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},0},
{<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},0},
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.1">>},0},
{<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.6">>},0},
{<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},0}]}.
[
{pkg_hash,[
{<<"certifi">>, <<"6F2A475689DD47F19FB74334859D460A2DC4E3252A3324BD2111B8F0429E7E21">>},
{<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>},
{<<"metrics">>, <<"25F094DEA2CDA98213CECC3AEFF09E940299D950904393B2A29D191C346A8486">>},
{<<"mimerl">>, <<"67E2D3F571088D5CFD3E550C383094B47159F3EEE8FFA08E64106CDF5E981BE3">>},
{<<"parse_trans">>, <<"16328AB840CC09919BD10DAB29E431DA3AF9E9E7E7E6F0089DD5A2D2820011D8">>},
{<<"ssl_verify_fun">>, <<"CF344F5692C82D2CD7554F5EC8FD961548D4FD09E7D22F5B62482E5AEAEBD4B0">>},
{<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}]},
{pkg_hash_ext,[
{<<"certifi">>, <<"266DA46BDB06D6C6D35FDE799BCB28D36D985D424AD7C08B5BB48F5B5CDD4641">>},
{<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>},
{<<"metrics">>, <<"69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16">>},
{<<"mimerl">>, <<"F278585650AA581986264638EBF698F8BB19DF297F66AD91B18910DFC6E19323">>},
{<<"parse_trans">>, <<"07CD9577885F56362D414E8C4C4E6BDF10D43A8767ABB92D24CBE8B24C54888B">>},
{<<"ssl_verify_fun">>, <<"BDB0D2471F453C88FF3908E7686F86F9BE327D065CC1EC16FA4540197EA04680">>},
{<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}]}
].