mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 10:36:45 +01:00
feat: implement haskell support (#1096)
This commit is contained in:
parent
00e12329d0
commit
9b1adce19a
@ -37,6 +37,7 @@ A CLI tool and Go library for generating a Software Bill of Materials (SBOM) fro
|
|||||||
- Dotnet (deps.json)
|
- Dotnet (deps.json)
|
||||||
- Objective-C (cocoapods)
|
- Objective-C (cocoapods)
|
||||||
- Go (go.mod, Go binaries)
|
- Go (go.mod, Go binaries)
|
||||||
|
- Haskell (cabal, stack)
|
||||||
- Java (jar, ear, war, par, sar)
|
- Java (jar, ear, war, par, sar)
|
||||||
- JavaScript (npm, yarn)
|
- JavaScript (npm, yarn)
|
||||||
- Jenkins Plugins (jpi, hpi)
|
- Jenkins Plugins (jpi, hpi)
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:funlen
|
||||||
func SourceInfo(p pkg.Package) string {
|
func SourceInfo(p pkg.Package) string {
|
||||||
answer := ""
|
answer := ""
|
||||||
switch p.Type {
|
switch p.Type {
|
||||||
@ -41,6 +42,8 @@ func SourceInfo(p pkg.Package) string {
|
|||||||
answer = "acquired package info from conan manifest"
|
answer = "acquired package info from conan manifest"
|
||||||
case pkg.PortagePkg:
|
case pkg.PortagePkg:
|
||||||
answer = "acquired package info from portage DB"
|
answer = "acquired package info from portage DB"
|
||||||
|
case pkg.HackagePkg:
|
||||||
|
answer = "acquired package info from cabal or stack manifest files"
|
||||||
default:
|
default:
|
||||||
answer = "acquired package info from the following paths"
|
answer = "acquired package info from the following paths"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -174,6 +174,14 @@ func Test_SourceInfo(t *testing.T) {
|
|||||||
"from portage DB",
|
"from portage DB",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: pkg.Package{
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
},
|
||||||
|
expected: []string{
|
||||||
|
"from cabal or stack manifest files",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
var pkgTypes []pkg.Type
|
var pkgTypes []pkg.Type
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|||||||
@ -169,6 +169,12 @@ func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.Metadata = payload
|
p.Metadata = payload
|
||||||
|
case pkg.HackageMetadataType:
|
||||||
|
var payload pkg.HackageMetadata
|
||||||
|
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.Metadata = payload
|
||||||
default:
|
default:
|
||||||
log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID)
|
log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg/cataloger/deb"
|
"github.com/anchore/syft/syft/pkg/cataloger/deb"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/dotnet"
|
"github.com/anchore/syft/syft/pkg/cataloger/dotnet"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/golang"
|
"github.com/anchore/syft/syft/pkg/cataloger/golang"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/haskell"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/php"
|
"github.com/anchore/syft/syft/pkg/cataloger/php"
|
||||||
@ -82,6 +83,7 @@ func DirectoryCatalogers(cfg Config) []Cataloger {
|
|||||||
swift.NewCocoapodsCataloger(),
|
swift.NewCocoapodsCataloger(),
|
||||||
cpp.NewConanfileCataloger(),
|
cpp.NewConanfileCataloger(),
|
||||||
portage.NewPortageCataloger(),
|
portage.NewPortageCataloger(),
|
||||||
|
haskell.NewHackageCataloger(),
|
||||||
}, cfg.Catalogers)
|
}, cfg.Catalogers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +112,7 @@ func AllCatalogers(cfg Config) []Cataloger {
|
|||||||
swift.NewCocoapodsCataloger(),
|
swift.NewCocoapodsCataloger(),
|
||||||
cpp.NewConanfileCataloger(),
|
cpp.NewConanfileCataloger(),
|
||||||
portage.NewPortageCataloger(),
|
portage.NewPortageCataloger(),
|
||||||
|
haskell.NewHackageCataloger(),
|
||||||
}, cfg.Catalogers)
|
}, cfg.Catalogers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
syft/pkg/cataloger/haskell/cataloger.go
Normal file
15
syft/pkg/cataloger/haskell/cataloger.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package haskell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewHackageCataloger returns a new Haskell cataloger object.
|
||||||
|
func NewHackageCataloger() *common.GenericCataloger {
|
||||||
|
globParsers := map[string]common.ParserFn{
|
||||||
|
"**/stack.yaml": parseStackYaml,
|
||||||
|
"**/stack.yaml.lock": parseStackLock,
|
||||||
|
"**/cabal.project.freeze": parseCabalFreeze,
|
||||||
|
}
|
||||||
|
return common.NewGenericCataloger(nil, globParsers, "hackage-cataloger")
|
||||||
|
}
|
||||||
53
syft/pkg/cataloger/haskell/parse_cabal_freeze.go
Normal file
53
syft/pkg/cataloger/haskell/parse_cabal_freeze.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package haskell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// integrity check
|
||||||
|
var _ common.ParserFn = parseCabalFreeze
|
||||||
|
|
||||||
|
// parseCabalFreeze is a parser function for cabal.project.freeze contents, returning all packages discovered.
|
||||||
|
func parseCabalFreeze(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||||
|
r := bufio.NewReader(reader)
|
||||||
|
pkgs := []*pkg.Package{}
|
||||||
|
for {
|
||||||
|
line, err := r.ReadString('\n')
|
||||||
|
switch {
|
||||||
|
case errors.Is(io.EOF, err):
|
||||||
|
return pkgs, nil, nil
|
||||||
|
case err != nil:
|
||||||
|
return nil, nil, fmt.Errorf("failed to parse cabal.project.freeze file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(line, "any.") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
startPkgEncoding, endPkgEncoding := strings.Index(line, "any.")+4, strings.Index(line, ",")
|
||||||
|
line = line[startPkgEncoding:endPkgEncoding]
|
||||||
|
splits := strings.Split(line, " ==")
|
||||||
|
|
||||||
|
pkgName, pkgVersion := splits[0], splits[1]
|
||||||
|
pkgs = append(pkgs, &pkg.Package{
|
||||||
|
Name: pkgName,
|
||||||
|
Version: pkgVersion,
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: pkgName,
|
||||||
|
Version: pkgVersion,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
151
syft/pkg/cataloger/haskell/parse_cabal_freeze_test.go
Normal file
151
syft/pkg/cataloger/haskell/parse_cabal_freeze_test.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package haskell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/go-test/deep"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseCabalFreeze(t *testing.T) {
|
||||||
|
expected := []*pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "Cabal",
|
||||||
|
Version: "3.2.1.0",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "Cabal",
|
||||||
|
Version: "3.2.1.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Diff",
|
||||||
|
Version: "0.4.1",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "Diff",
|
||||||
|
Version: "0.4.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "HTTP",
|
||||||
|
Version: "4000.3.16",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "HTTP",
|
||||||
|
Version: "4000.3.16",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "HUnit",
|
||||||
|
Version: "1.6.2.0",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "HUnit",
|
||||||
|
Version: "1.6.2.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "OneTuple",
|
||||||
|
Version: "0.3.1",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "OneTuple",
|
||||||
|
Version: "0.3.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Only",
|
||||||
|
Version: "0.1",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "Only",
|
||||||
|
Version: "0.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "PyF",
|
||||||
|
Version: "0.10.2.0",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "PyF",
|
||||||
|
Version: "0.10.2.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "QuickCheck",
|
||||||
|
Version: "2.14.2",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "QuickCheck",
|
||||||
|
Version: "2.14.2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "RSA",
|
||||||
|
Version: "2.4.1",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "RSA",
|
||||||
|
Version: "2.4.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "SHA",
|
||||||
|
Version: "1.6.4.4",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "SHA",
|
||||||
|
Version: "1.6.4.4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Spock",
|
||||||
|
Version: "0.14.0.0",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "Spock",
|
||||||
|
Version: "0.14.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fixture, err := os.Open("test-fixtures/cabal.project.freeze")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: no relationships are under test yet
|
||||||
|
actual, _, err := parseCabalFreeze(fixture.Name(), fixture)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
differences := deep.Equal(expected, actual)
|
||||||
|
if differences != nil {
|
||||||
|
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||||
|
}
|
||||||
|
}
|
||||||
90
syft/pkg/cataloger/haskell/parse_stack_lock.go
Normal file
90
syft/pkg/cataloger/haskell/parse_stack_lock.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package haskell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// integrity check
|
||||||
|
var _ common.ParserFn = parseStackLock
|
||||||
|
|
||||||
|
type stackLock struct {
|
||||||
|
Packages []stackPackage `yaml:"packages"`
|
||||||
|
Snapshots []stackSnapshot `yaml:"snapshots"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type stackPackage struct {
|
||||||
|
Completed completedPackage `yaml:"completed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type completedPackage struct {
|
||||||
|
Hackage string `yaml:"hackage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type stackSnapshot struct {
|
||||||
|
Completed completedSnapshot `yaml:"completed"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type completedSnapshot struct {
|
||||||
|
URL string `yaml:"url"`
|
||||||
|
Sha string `yaml:"sha256"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseStackPackageEncoding(pkgEncoding string) (name, version, hash string) {
|
||||||
|
lastDashIdx := strings.LastIndex(pkgEncoding, "-")
|
||||||
|
name = pkgEncoding[:lastDashIdx]
|
||||||
|
remainingEncoding := pkgEncoding[lastDashIdx+1:]
|
||||||
|
encodingSplits := strings.Split(remainingEncoding, "@")
|
||||||
|
version = encodingSplits[0]
|
||||||
|
startHash, endHash := strings.Index(encodingSplits[1], ":")+1, strings.Index(encodingSplits[1], ",")
|
||||||
|
hash = encodingSplits[1][startHash:endHash]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseStackLock is a parser function for stack.yaml.lock contents, returning all packages discovered.
|
||||||
|
func parseStackLock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||||
|
bytes, err := io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to load stack.yaml.lock file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var lockFile stackLock
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal(bytes, &lockFile); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to parse stack.yaml.lock file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pkgs []*pkg.Package
|
||||||
|
snapshotURL string
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, snap := range lockFile.Snapshots {
|
||||||
|
snapshotURL = snap.Completed.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pack := range lockFile.Packages {
|
||||||
|
pkgName, pkgVersion, pkgHash := parseStackPackageEncoding(pack.Completed.Hackage)
|
||||||
|
pkgs = append(pkgs, &pkg.Package{
|
||||||
|
Name: pkgName,
|
||||||
|
Version: pkgVersion,
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: pkgName,
|
||||||
|
Version: pkgVersion,
|
||||||
|
PkgHash: &pkgHash,
|
||||||
|
SnapshotURL: &snapshotURL,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs, nil, nil
|
||||||
|
}
|
||||||
152
syft/pkg/cataloger/haskell/parse_stack_lock_test.go
Normal file
152
syft/pkg/cataloger/haskell/parse_stack_lock_test.go
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
package haskell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/go-test/deep"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fixtureP(str string) *string {
|
||||||
|
return &str
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseStackLock(t *testing.T) {
|
||||||
|
url := "https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/14.yaml"
|
||||||
|
expected := []*pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "HTTP",
|
||||||
|
Version: "4000.3.16",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "HTTP",
|
||||||
|
Version: "4000.3.16",
|
||||||
|
PkgHash: fixtureP("6042643c15a0b43e522a6693f1e322f05000d519543a84149cb80aeffee34f71"),
|
||||||
|
SnapshotURL: &url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "configurator-pg",
|
||||||
|
Version: "0.2.6",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "configurator-pg",
|
||||||
|
Version: "0.2.6",
|
||||||
|
PkgHash: fixtureP("cd9b06a458428e493a4d6def725af7ab1ab0fef678fbd871f9586fc7f9aa70be"),
|
||||||
|
SnapshotURL: &url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "hasql-dynamic-statements",
|
||||||
|
Version: "0.3.1.1",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "hasql-dynamic-statements",
|
||||||
|
Version: "0.3.1.1",
|
||||||
|
PkgHash: fixtureP("2cfe6e75990e690f595a87cbe553f2e90fcd738610f6c66749c81cc4396b2cc4"),
|
||||||
|
SnapshotURL: &url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "hasql-implicits",
|
||||||
|
Version: "0.1.0.4",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "hasql-implicits",
|
||||||
|
Version: "0.1.0.4",
|
||||||
|
PkgHash: fixtureP("0848d3cbc9d94e1e539948fa0be4d0326b26335034161bf8076785293444ca6f"),
|
||||||
|
SnapshotURL: &url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "hasql-pool",
|
||||||
|
Version: "0.5.2.2",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "hasql-pool",
|
||||||
|
Version: "0.5.2.2",
|
||||||
|
PkgHash: fixtureP("b56d4dea112d97a2ef4b2749508c0ca646828cb2d77b827e8dc433d249bb2062"),
|
||||||
|
SnapshotURL: &url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "lens-aeson",
|
||||||
|
Version: "1.1.3",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "lens-aeson",
|
||||||
|
Version: "1.1.3",
|
||||||
|
PkgHash: fixtureP("52c8eaecd2d1c2a969c0762277c4a8ee72c339a686727d5785932e72ef9c3050"),
|
||||||
|
SnapshotURL: &url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "optparse-applicative",
|
||||||
|
Version: "0.16.1.0",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "optparse-applicative",
|
||||||
|
Version: "0.16.1.0",
|
||||||
|
PkgHash: fixtureP("418c22ed6a19124d457d96bc66bd22c93ac22fad0c7100fe4972bbb4ac989731"),
|
||||||
|
SnapshotURL: &url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "protolude",
|
||||||
|
Version: "0.3.2",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "protolude",
|
||||||
|
Version: "0.3.2",
|
||||||
|
PkgHash: fixtureP("2a38b3dad40d238ab644e234b692c8911423f9d3ed0e36b62287c4a698d92cd1"),
|
||||||
|
SnapshotURL: &url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "ptr",
|
||||||
|
Version: "0.16.8.2",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "ptr",
|
||||||
|
Version: "0.16.8.2",
|
||||||
|
PkgHash: fixtureP("708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac"),
|
||||||
|
SnapshotURL: &url,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fixture, err := os.Open("test-fixtures/stack.yaml.lock")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: no relationships are under test yet
|
||||||
|
actual, _, err := parseStackLock(fixture.Name(), fixture)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
differences := deep.Equal(expected, actual)
|
||||||
|
if differences != nil {
|
||||||
|
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||||
|
}
|
||||||
|
}
|
||||||
54
syft/pkg/cataloger/haskell/parse_stack_yaml.go
Normal file
54
syft/pkg/cataloger/haskell/parse_stack_yaml.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package haskell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// integrity check
|
||||||
|
var _ common.ParserFn = parseStackYaml
|
||||||
|
|
||||||
|
type stackYaml struct {
|
||||||
|
ExtraDeps []string `yaml:"extra-deps"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseStackYaml is a parser function for stack.yaml contents, returning all packages discovered.
|
||||||
|
func parseStackYaml(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||||
|
bytes, err := io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to load stack.yaml file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var stackFile stackYaml
|
||||||
|
|
||||||
|
if err := yaml.Unmarshal(bytes, &stackFile); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to parse stack.yaml file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pkgs []*pkg.Package
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, dep := range stackFile.ExtraDeps {
|
||||||
|
pkgName, pkgVersion, pkgHash := parseStackPackageEncoding(dep)
|
||||||
|
pkgs = append(pkgs, &pkg.Package{
|
||||||
|
Name: pkgName,
|
||||||
|
Version: pkgVersion,
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: pkgName,
|
||||||
|
Version: pkgVersion,
|
||||||
|
PkgHash: &pkgHash,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs, nil, nil
|
||||||
|
}
|
||||||
126
syft/pkg/cataloger/haskell/parse_stack_yaml_test.go
Normal file
126
syft/pkg/cataloger/haskell/parse_stack_yaml_test.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package haskell
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/go-test/deep"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseStackYaml(t *testing.T) {
|
||||||
|
expected := []*pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "ShellCheck",
|
||||||
|
Version: "0.8.0",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "ShellCheck",
|
||||||
|
Version: "0.8.0",
|
||||||
|
PkgHash: fixtureP("353c9322847b661e4c6f7c83c2acf8e5c08b682fbe516c7d46c29605937543df"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "colourista",
|
||||||
|
Version: "0.1.0.1",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "colourista",
|
||||||
|
Version: "0.1.0.1",
|
||||||
|
PkgHash: fixtureP("98353ee0e2f5d97d2148513f084c1cd37dfda03e48aa9dd7a017c9d9c0ba710e"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "language-docker",
|
||||||
|
Version: "11.0.0",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "language-docker",
|
||||||
|
Version: "11.0.0",
|
||||||
|
PkgHash: fixtureP("3406ff0c1d592490f53ead8cf2cd22bdf3d79fd125ccaf3add683f6d71c24d55"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "spdx",
|
||||||
|
Version: "1.0.0.2",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "spdx",
|
||||||
|
Version: "1.0.0.2",
|
||||||
|
PkgHash: fixtureP("7dfac9b454ff2da0abb7560f0ffbe00ae442dd5cb76e8be469f77e6988a70fed"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "hspec",
|
||||||
|
Version: "2.9.4",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "hspec",
|
||||||
|
Version: "2.9.4",
|
||||||
|
PkgHash: fixtureP("658a6a74d5a70c040edd6df2a12228c6d9e63082adaad1ed4d0438ad082a0ef3"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "hspec-core",
|
||||||
|
Version: "2.9.4",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "hspec-core",
|
||||||
|
Version: "2.9.4",
|
||||||
|
PkgHash: fixtureP("a126e9087409fef8dcafcd2f8656456527ac7bb163ed4d9cb3a57589042a5fe8"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "hspec-discover",
|
||||||
|
Version: "2.9.4",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "hspec-discover",
|
||||||
|
Version: "2.9.4",
|
||||||
|
PkgHash: fixtureP("fbcf49ecfc3d4da53e797fd0275264cba776ffa324ee223e2a3f4ec2d2c9c4a6"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "stm",
|
||||||
|
Version: "2.5.0.2",
|
||||||
|
Language: pkg.Haskell,
|
||||||
|
Type: pkg.HackagePkg,
|
||||||
|
MetadataType: pkg.HackageMetadataType,
|
||||||
|
Metadata: pkg.HackageMetadata{
|
||||||
|
Name: "stm",
|
||||||
|
Version: "2.5.0.2",
|
||||||
|
PkgHash: fixtureP("e4dc6473faaa75fbd7eccab4e3ee1d651d75bb0e49946ef0b8b751ccde771a55"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fixture, err := os.Open("test-fixtures/stack.yaml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: no relationships are under test yet
|
||||||
|
actual, _, err := parseStackYaml(fixture.Name(), fixture)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
differences := deep.Equal(expected, actual)
|
||||||
|
if differences != nil {
|
||||||
|
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
active-repositories: hackage.haskell.org:merge
|
||||||
|
constraints: any.Cabal ==3.2.1.0,
|
||||||
|
any.Diff ==0.4.1,
|
||||||
|
any.HTTP ==4000.3.16,
|
||||||
|
any.HUnit ==1.6.2.0,
|
||||||
|
any.OneTuple ==0.3.1,
|
||||||
|
tls +compat -hans +network,
|
||||||
|
any.Only ==0.1,
|
||||||
|
any.PyF ==0.10.2.0,
|
||||||
|
any.QuickCheck ==2.14.2,
|
||||||
|
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
|
||||||
|
any.RSA ==2.4.1,
|
||||||
|
any.SHA ==1.6.4.4,
|
||||||
|
void -safe,
|
||||||
|
any.Spock ==0.14.0.0,
|
||||||
|
|
||||||
|
index-state: hackage.haskell.org 2022-07-07T01:01:53Z
|
||||||
16
syft/pkg/cataloger/haskell/test-fixtures/stack.yaml
Normal file
16
syft/pkg/cataloger/haskell/test-fixtures/stack.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
flags: {}
|
||||||
|
extra-package-dbs: []
|
||||||
|
packages:
|
||||||
|
- .
|
||||||
|
resolver: lts-18.28
|
||||||
|
extra-deps:
|
||||||
|
- ShellCheck-0.8.0@sha256:353c9322847b661e4c6f7c83c2acf8e5c08b682fbe516c7d46c29605937543df,3297
|
||||||
|
- colourista-0.1.0.1@sha256:98353ee0e2f5d97d2148513f084c1cd37dfda03e48aa9dd7a017c9d9c0ba710e,3307
|
||||||
|
- language-docker-11.0.0@sha256:3406ff0c1d592490f53ead8cf2cd22bdf3d79fd125ccaf3add683f6d71c24d55,3883
|
||||||
|
- spdx-1.0.0.2@sha256:7dfac9b454ff2da0abb7560f0ffbe00ae442dd5cb76e8be469f77e6988a70fed,2008
|
||||||
|
- hspec-2.9.4@sha256:658a6a74d5a70c040edd6df2a12228c6d9e63082adaad1ed4d0438ad082a0ef3,1709
|
||||||
|
- hspec-core-2.9.4@sha256:a126e9087409fef8dcafcd2f8656456527ac7bb163ed4d9cb3a57589042a5fe8,6498
|
||||||
|
- hspec-discover-2.9.4@sha256:fbcf49ecfc3d4da53e797fd0275264cba776ffa324ee223e2a3f4ec2d2c9c4a6,2165
|
||||||
|
- stm-2.5.0.2@sha256:e4dc6473faaa75fbd7eccab4e3ee1d651d75bb0e49946ef0b8b751ccde771a55,2314
|
||||||
|
ghc-options:
|
||||||
|
"$everything": -haddock
|
||||||
75
syft/pkg/cataloger/haskell/test-fixtures/stack.yaml.lock
Normal file
75
syft/pkg/cataloger/haskell/test-fixtures/stack.yaml.lock
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# This file was autogenerated by Stack.
|
||||||
|
# You should not edit this file by hand.
|
||||||
|
# For more information, please see the documentation at:
|
||||||
|
# https://docs.haskellstack.org/en/stable/lock_files
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- completed:
|
||||||
|
hackage: HTTP-4000.3.16@sha256:6042643c15a0b43e522a6693f1e322f05000d519543a84149cb80aeffee34f71,5947
|
||||||
|
pantry-tree:
|
||||||
|
size: 1428
|
||||||
|
sha256: b73a7f6d21cf20bbf819e19039409c9010efb5000d2b72cdd8fd67a9027c14e8
|
||||||
|
original:
|
||||||
|
hackage: HTTP-4000.3.16@sha256:6042643c15a0b43e522a6693f1e322f05000d519543a84149cb80aeffee34f71,5947
|
||||||
|
- completed:
|
||||||
|
hackage: configurator-pg-0.2.6@sha256:cd9b06a458428e493a4d6def725af7ab1ab0fef678fbd871f9586fc7f9aa70be,2849
|
||||||
|
pantry-tree:
|
||||||
|
size: 2463
|
||||||
|
sha256: 97efe7a22afc93033bda5adcffdabc0f1c30dc32b2c3ba02114ce7cd74c942fd
|
||||||
|
original:
|
||||||
|
hackage: configurator-pg-0.2.6@sha256:cd9b06a458428e493a4d6def725af7ab1ab0fef678fbd871f9586fc7f9aa70be,2849
|
||||||
|
- completed:
|
||||||
|
hackage: hasql-dynamic-statements-0.3.1.1@sha256:2cfe6e75990e690f595a87cbe553f2e90fcd738610f6c66749c81cc4396b2cc4,2675
|
||||||
|
pantry-tree:
|
||||||
|
size: 595
|
||||||
|
sha256: b84ae10a5c776f88f546df73bc957a35e61056400b7e805dad0b254612907e97
|
||||||
|
original:
|
||||||
|
hackage: hasql-dynamic-statements-0.3.1.1@sha256:2cfe6e75990e690f595a87cbe553f2e90fcd738610f6c66749c81cc4396b2cc4,2675
|
||||||
|
- completed:
|
||||||
|
hackage: hasql-implicits-0.1.0.4@sha256:0848d3cbc9d94e1e539948fa0be4d0326b26335034161bf8076785293444ca6f,1361
|
||||||
|
pantry-tree:
|
||||||
|
size: 264
|
||||||
|
sha256: d49af8f8749ab7039fa668af4b78f997f7fa2928b4aded6798f573a3d08e76a0
|
||||||
|
original:
|
||||||
|
hackage: hasql-implicits-0.1.0.4@sha256:0848d3cbc9d94e1e539948fa0be4d0326b26335034161bf8076785293444ca6f,1361
|
||||||
|
- completed:
|
||||||
|
hackage: hasql-pool-0.5.2.2@sha256:b56d4dea112d97a2ef4b2749508c0ca646828cb2d77b827e8dc433d249bb2062,2438
|
||||||
|
pantry-tree:
|
||||||
|
size: 412
|
||||||
|
sha256: 2741a33f947d28b4076c798c20c1f646beecd21f5eaf522c8256cbeb34d4d6d0
|
||||||
|
original:
|
||||||
|
hackage: hasql-pool-0.5.2.2@sha256:b56d4dea112d97a2ef4b2749508c0ca646828cb2d77b827e8dc433d249bb2062,2438
|
||||||
|
- completed:
|
||||||
|
hackage: lens-aeson-1.1.3@sha256:52c8eaecd2d1c2a969c0762277c4a8ee72c339a686727d5785932e72ef9c3050,1764
|
||||||
|
pantry-tree:
|
||||||
|
size: 541
|
||||||
|
sha256: b31392b78f2a03111c805f4400007778eb93b49f998ab41dfbebaaf9b5526bad
|
||||||
|
original:
|
||||||
|
hackage: lens-aeson-1.1.3@sha256:52c8eaecd2d1c2a969c0762277c4a8ee72c339a686727d5785932e72ef9c3050,1764
|
||||||
|
- completed:
|
||||||
|
hackage: optparse-applicative-0.16.1.0@sha256:418c22ed6a19124d457d96bc66bd22c93ac22fad0c7100fe4972bbb4ac989731,4982
|
||||||
|
pantry-tree:
|
||||||
|
size: 2979
|
||||||
|
sha256: dd092d843091c08691485d68a1908517079b1bc6f3d73928f37635a19dc27fc1
|
||||||
|
original:
|
||||||
|
hackage: optparse-applicative-0.16.1.0@sha256:418c22ed6a19124d457d96bc66bd22c93ac22fad0c7100fe4972bbb4ac989731,4982
|
||||||
|
- completed:
|
||||||
|
hackage: protolude-0.3.2@sha256:2a38b3dad40d238ab644e234b692c8911423f9d3ed0e36b62287c4a698d92cd1,2240
|
||||||
|
pantry-tree:
|
||||||
|
size: 1594
|
||||||
|
sha256: a36d2912ac552d950ba4476de7d950b56b82dd28e48b9f4d0efee938f10bc525
|
||||||
|
original:
|
||||||
|
hackage: protolude-0.3.2@sha256:2a38b3dad40d238ab644e234b692c8911423f9d3ed0e36b62287c4a698d92cd1,2240
|
||||||
|
- completed:
|
||||||
|
hackage: ptr-0.16.8.2@sha256:708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac,3959
|
||||||
|
pantry-tree:
|
||||||
|
size: 1303
|
||||||
|
sha256: 557c438345de19f82bf01d676100da2a191ef06f624e7a4b90b09ac17cbb52a5
|
||||||
|
original:
|
||||||
|
hackage: ptr-0.16.8.2@sha256:708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac,3959
|
||||||
|
snapshots:
|
||||||
|
- completed:
|
||||||
|
size: 618951
|
||||||
|
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/14.yaml
|
||||||
|
sha256: 4c31d4ef975b0211078862566aedf3b82b6cea569fc2cde4c72a51e5a8d236ce
|
||||||
|
original: lts-19.14
|
||||||
28
syft/pkg/hackage_metadata.go
Normal file
28
syft/pkg/hackage_metadata.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package pkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/packageurl-go"
|
||||||
|
"github.com/anchore/syft/syft/linux"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ urlIdentifier = (*HackageMetadata)(nil)
|
||||||
|
|
||||||
|
type HackageMetadata struct {
|
||||||
|
Name string `mapstructure:"name" json:"name"`
|
||||||
|
Version string `mapstructure:"version" json:"version"`
|
||||||
|
PkgHash *string `mapstructure:"pkgHash" json:"pkgHash,omitempty"`
|
||||||
|
SnapshotURL *string `mapstructure:"snapshotURL" json:"snapshotURL,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m HackageMetadata) PackageURL(_ *linux.Release) string {
|
||||||
|
var qualifiers packageurl.Qualifiers
|
||||||
|
|
||||||
|
return packageurl.NewPackageURL(
|
||||||
|
packageurl.TypeHackage,
|
||||||
|
"",
|
||||||
|
m.Name,
|
||||||
|
m.Version,
|
||||||
|
qualifiers,
|
||||||
|
"",
|
||||||
|
).ToString()
|
||||||
|
}
|
||||||
@ -23,6 +23,7 @@ const (
|
|||||||
Dotnet Language = "dotnet"
|
Dotnet Language = "dotnet"
|
||||||
Swift Language = "swift"
|
Swift Language = "swift"
|
||||||
CPP Language = "c++"
|
CPP Language = "c++"
|
||||||
|
Haskell Language = "haskell"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllLanguages is a set of all programming languages detected by syft.
|
// AllLanguages is a set of all programming languages detected by syft.
|
||||||
@ -38,6 +39,7 @@ var AllLanguages = []Language{
|
|||||||
Dotnet,
|
Dotnet,
|
||||||
Swift,
|
Swift,
|
||||||
CPP,
|
CPP,
|
||||||
|
Haskell,
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of the language.
|
// String returns the string representation of the language.
|
||||||
@ -78,6 +80,8 @@ func LanguageByName(name string) Language {
|
|||||||
return Swift
|
return Swift
|
||||||
case packageurl.TypeConan, string(CPP):
|
case packageurl.TypeConan, string(CPP):
|
||||||
return CPP
|
return CPP
|
||||||
|
case packageurl.TypeHackage, string(Haskell):
|
||||||
|
return Haskell
|
||||||
default:
|
default:
|
||||||
return UnknownLanguage
|
return UnknownLanguage
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,10 @@ func TestLanguageFromPURL(t *testing.T) {
|
|||||||
purl: "pkg:conan/catch2@2.13.8",
|
purl: "pkg:conan/catch2@2.13.8",
|
||||||
want: CPP,
|
want: CPP,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
purl: "pkg:hackage/HTTP@4000.3.16",
|
||||||
|
want: Haskell,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var languages []string
|
var languages []string
|
||||||
@ -211,6 +215,14 @@ func TestLanguageByName(t *testing.T) {
|
|||||||
name: "c++",
|
name: "c++",
|
||||||
language: CPP,
|
language: CPP,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "hackage",
|
||||||
|
language: Haskell,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "haskell",
|
||||||
|
language: Haskell,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|||||||
@ -28,6 +28,7 @@ const (
|
|||||||
CocoapodsMetadataType MetadataType = "CocoapodsMetadataType"
|
CocoapodsMetadataType MetadataType = "CocoapodsMetadataType"
|
||||||
ConanaMetadataType MetadataType = "ConanaMetadataType"
|
ConanaMetadataType MetadataType = "ConanaMetadataType"
|
||||||
PortageMetadataType MetadataType = "PortageMetadata"
|
PortageMetadataType MetadataType = "PortageMetadata"
|
||||||
|
HackageMetadataType MetadataType = "HackageMetadataType"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AllMetadataTypes = []MetadataType{
|
var AllMetadataTypes = []MetadataType{
|
||||||
@ -48,6 +49,7 @@ var AllMetadataTypes = []MetadataType{
|
|||||||
CocoapodsMetadataType,
|
CocoapodsMetadataType,
|
||||||
ConanaMetadataType,
|
ConanaMetadataType,
|
||||||
PortageMetadataType,
|
PortageMetadataType,
|
||||||
|
HackageMetadataType,
|
||||||
}
|
}
|
||||||
|
|
||||||
var MetadataTypeByName = map[MetadataType]reflect.Type{
|
var MetadataTypeByName = map[MetadataType]reflect.Type{
|
||||||
@ -68,4 +70,5 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{
|
|||||||
CocoapodsMetadataType: reflect.TypeOf(CocoapodsMetadata{}),
|
CocoapodsMetadataType: reflect.TypeOf(CocoapodsMetadata{}),
|
||||||
ConanaMetadataType: reflect.TypeOf(ConanMetadata{}),
|
ConanaMetadataType: reflect.TypeOf(ConanMetadata{}),
|
||||||
PortageMetadataType: reflect.TypeOf(PortageMetadata{}),
|
PortageMetadataType: reflect.TypeOf(PortageMetadata{}),
|
||||||
|
HackageMetadataType: reflect.TypeOf(HackageMetadata{}),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ const (
|
|||||||
CocoapodsPkg Type = "pod"
|
CocoapodsPkg Type = "pod"
|
||||||
ConanPkg Type = "conan"
|
ConanPkg Type = "conan"
|
||||||
PortagePkg Type = "portage"
|
PortagePkg Type = "portage"
|
||||||
|
HackagePkg Type = "hackage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllPkgs represents all supported package types
|
// AllPkgs represents all supported package types
|
||||||
@ -48,6 +49,7 @@ var AllPkgs = []Type{
|
|||||||
CocoapodsPkg,
|
CocoapodsPkg,
|
||||||
ConanPkg,
|
ConanPkg,
|
||||||
PortagePkg,
|
PortagePkg,
|
||||||
|
HackagePkg,
|
||||||
}
|
}
|
||||||
|
|
||||||
// PackageURLType returns the PURL package type for the current package.
|
// PackageURLType returns the PURL package type for the current package.
|
||||||
@ -85,6 +87,8 @@ func (t Type) PackageURLType() string {
|
|||||||
return packageurl.TypeConan
|
return packageurl.TypeConan
|
||||||
case PortagePkg:
|
case PortagePkg:
|
||||||
return "portage"
|
return "portage"
|
||||||
|
case HackagePkg:
|
||||||
|
return packageurl.TypeHackage
|
||||||
default:
|
default:
|
||||||
// TODO: should this be a "generic" purl type instead?
|
// TODO: should this be a "generic" purl type instead?
|
||||||
return ""
|
return ""
|
||||||
@ -132,6 +136,8 @@ func TypeByName(name string) Type {
|
|||||||
return CocoapodsPkg
|
return CocoapodsPkg
|
||||||
case packageurl.TypeConan:
|
case packageurl.TypeConan:
|
||||||
return ConanPkg
|
return ConanPkg
|
||||||
|
case packageurl.TypeHackage:
|
||||||
|
return HackagePkg
|
||||||
case "portage":
|
case "portage":
|
||||||
return PortagePkg
|
return PortagePkg
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -76,6 +76,10 @@ func TestTypeFromPURL(t *testing.T) {
|
|||||||
purl: "pkg:conan/catch2@2.13.8",
|
purl: "pkg:conan/catch2@2.13.8",
|
||||||
expected: ConanPkg,
|
expected: ConanPkg,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
purl: "pkg:hackage/HTTP@4000.3.16",
|
||||||
|
expected: HackagePkg,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var pkgTypes []string
|
var pkgTypes []string
|
||||||
|
|||||||
@ -246,6 +246,21 @@ func TestPackageURL(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expected: "pkg:conan/catch2@2.13.8",
|
expected: "pkg:conan/catch2@2.13.8",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "hackage",
|
||||||
|
pkg: Package{
|
||||||
|
Name: "HTTP",
|
||||||
|
Version: "4000.3.16",
|
||||||
|
Type: HackagePkg,
|
||||||
|
Language: Haskell,
|
||||||
|
MetadataType: HackageMetadataType,
|
||||||
|
Metadata: HackageMetadata{
|
||||||
|
Name: "HTTP",
|
||||||
|
Version: "4000.3.16",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "pkg:hackage/HTTP@4000.3.16",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var pkgTypes []string
|
var pkgTypes []string
|
||||||
|
|||||||
@ -281,6 +281,40 @@ var dirOnlyTestCases = []testCase{
|
|||||||
"TinyConstraints": "4.0.2",
|
"TinyConstraints": "4.0.2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "find hackage packages",
|
||||||
|
pkgType: pkg.HackagePkg,
|
||||||
|
pkgLanguage: pkg.Haskell,
|
||||||
|
pkgInfo: map[string]string{
|
||||||
|
"Cabal": "3.2.1.0",
|
||||||
|
"Diff": "0.4.1",
|
||||||
|
"HTTP": "4000.3.16",
|
||||||
|
"HUnit": "1.6.2.0",
|
||||||
|
"OneTuple": "0.3.1",
|
||||||
|
"Only": "0.1",
|
||||||
|
"PyF": "0.10.2.0",
|
||||||
|
"QuickCheck": "2.14.2",
|
||||||
|
"RSA": "2.4.1",
|
||||||
|
"SHA": "1.6.4.4",
|
||||||
|
"Spock": "0.14.0.0",
|
||||||
|
"ShellCheck": "0.8.0",
|
||||||
|
"colourista": "0.1.0.1",
|
||||||
|
"language-docker": "11.0.0",
|
||||||
|
"spdx": "1.0.0.2",
|
||||||
|
"hspec": "2.9.4",
|
||||||
|
"hspec-core": "2.9.4",
|
||||||
|
"hspec-discover": "2.9.4",
|
||||||
|
"stm": "2.5.0.2",
|
||||||
|
"configurator-pg": "0.2.6",
|
||||||
|
"hasql-dynamic-statements": "0.3.1.1",
|
||||||
|
"hasql-implicits": "0.1.0.4",
|
||||||
|
"hasql-pool": "0.5.2.2",
|
||||||
|
"lens-aeson": "1.1.3",
|
||||||
|
"optparse-applicative": "0.16.1.0",
|
||||||
|
"protolude": "0.3.2",
|
||||||
|
"ptr": "0.16.8.2",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var commonTestCases = []testCase{
|
var commonTestCases = []testCase{
|
||||||
|
|||||||
@ -69,6 +69,7 @@ func TestPkgCoverageImage(t *testing.T) {
|
|||||||
definedLanguages.Remove(pkg.Dotnet.String())
|
definedLanguages.Remove(pkg.Dotnet.String())
|
||||||
definedLanguages.Remove(string(pkg.Swift.String()))
|
definedLanguages.Remove(string(pkg.Swift.String()))
|
||||||
definedLanguages.Remove(pkg.CPP.String())
|
definedLanguages.Remove(pkg.CPP.String())
|
||||||
|
definedLanguages.Remove(pkg.Haskell.String())
|
||||||
|
|
||||||
observedPkgs := internal.NewStringSet()
|
observedPkgs := internal.NewStringSet()
|
||||||
definedPkgs := internal.NewStringSet()
|
definedPkgs := internal.NewStringSet()
|
||||||
@ -84,6 +85,7 @@ func TestPkgCoverageImage(t *testing.T) {
|
|||||||
definedPkgs.Remove(string(pkg.DotnetPkg))
|
definedPkgs.Remove(string(pkg.DotnetPkg))
|
||||||
definedPkgs.Remove(string(pkg.CocoapodsPkg))
|
definedPkgs.Remove(string(pkg.CocoapodsPkg))
|
||||||
definedPkgs.Remove(string(pkg.ConanPkg))
|
definedPkgs.Remove(string(pkg.ConanPkg))
|
||||||
|
definedPkgs.Remove(string(pkg.HackagePkg))
|
||||||
|
|
||||||
var cases []testCase
|
var cases []testCase
|
||||||
cases = append(cases, commonTestCases...)
|
cases = append(cases, commonTestCases...)
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
active-repositories: hackage.haskell.org:merge
|
||||||
|
constraints: any.Cabal ==3.2.1.0,
|
||||||
|
any.Diff ==0.4.1,
|
||||||
|
any.HUnit ==1.6.2.0,
|
||||||
|
any.OneTuple ==0.3.1,
|
||||||
|
tls +compat -hans +network,
|
||||||
|
any.Only ==0.1,
|
||||||
|
any.PyF ==0.10.2.0,
|
||||||
|
any.QuickCheck ==2.14.2,
|
||||||
|
semigroups +binary +bytestring -bytestring-builder +containers +deepseq +hashable +tagged +template-haskell +text +transformers +unordered-containers,
|
||||||
|
any.RSA ==2.4.1,
|
||||||
|
any.SHA ==1.6.4.4,
|
||||||
|
void -safe,
|
||||||
|
any.Spock ==0.14.0.0,
|
||||||
|
|
||||||
|
index-state: hackage.haskell.org 2022-07-07T01:01:53Z
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
flags: {}
|
||||||
|
extra-package-dbs: []
|
||||||
|
packages:
|
||||||
|
- .
|
||||||
|
resolver: lts-18.28
|
||||||
|
extra-deps:
|
||||||
|
- ShellCheck-0.8.0@sha256:353c9322847b661e4c6f7c83c2acf8e5c08b682fbe516c7d46c29605937543df,3297
|
||||||
|
- colourista-0.1.0.1@sha256:98353ee0e2f5d97d2148513f084c1cd37dfda03e48aa9dd7a017c9d9c0ba710e,3307
|
||||||
|
- language-docker-11.0.0@sha256:3406ff0c1d592490f53ead8cf2cd22bdf3d79fd125ccaf3add683f6d71c24d55,3883
|
||||||
|
- spdx-1.0.0.2@sha256:7dfac9b454ff2da0abb7560f0ffbe00ae442dd5cb76e8be469f77e6988a70fed,2008
|
||||||
|
- hspec-2.9.4@sha256:658a6a74d5a70c040edd6df2a12228c6d9e63082adaad1ed4d0438ad082a0ef3,1709
|
||||||
|
- hspec-core-2.9.4@sha256:a126e9087409fef8dcafcd2f8656456527ac7bb163ed4d9cb3a57589042a5fe8,6498
|
||||||
|
- hspec-discover-2.9.4@sha256:fbcf49ecfc3d4da53e797fd0275264cba776ffa324ee223e2a3f4ec2d2c9c4a6,2165
|
||||||
|
- stm-2.5.0.2@sha256:e4dc6473faaa75fbd7eccab4e3ee1d651d75bb0e49946ef0b8b751ccde771a55,2314
|
||||||
|
ghc-options:
|
||||||
|
"$everything": -haddock
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
# This file was autogenerated by Stack.
|
||||||
|
# You should not edit this file by hand.
|
||||||
|
# For more information, please see the documentation at:
|
||||||
|
# https://docs.haskellstack.org/en/stable/lock_files
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- completed:
|
||||||
|
hackage: HTTP-4000.3.16@sha256:6042643c15a0b43e522a6693f1e322f05000d519543a84149cb80aeffee34f71,5947
|
||||||
|
pantry-tree:
|
||||||
|
size: 1428
|
||||||
|
sha256: b73a7f6d21cf20bbf819e19039409c9010efb5000d2b72cdd8fd67a9027c14e8
|
||||||
|
original:
|
||||||
|
hackage: HTTP-4000.3.16@sha256:6042643c15a0b43e522a6693f1e322f05000d519543a84149cb80aeffee34f71,5947
|
||||||
|
- completed:
|
||||||
|
hackage: configurator-pg-0.2.6@sha256:cd9b06a458428e493a4d6def725af7ab1ab0fef678fbd871f9586fc7f9aa70be,2849
|
||||||
|
pantry-tree:
|
||||||
|
size: 2463
|
||||||
|
sha256: 97efe7a22afc93033bda5adcffdabc0f1c30dc32b2c3ba02114ce7cd74c942fd
|
||||||
|
original:
|
||||||
|
hackage: configurator-pg-0.2.6@sha256:cd9b06a458428e493a4d6def725af7ab1ab0fef678fbd871f9586fc7f9aa70be,2849
|
||||||
|
- completed:
|
||||||
|
hackage: hasql-dynamic-statements-0.3.1.1@sha256:2cfe6e75990e690f595a87cbe553f2e90fcd738610f6c66749c81cc4396b2cc4,2675
|
||||||
|
pantry-tree:
|
||||||
|
size: 595
|
||||||
|
sha256: b84ae10a5c776f88f546df73bc957a35e61056400b7e805dad0b254612907e97
|
||||||
|
original:
|
||||||
|
hackage: hasql-dynamic-statements-0.3.1.1@sha256:2cfe6e75990e690f595a87cbe553f2e90fcd738610f6c66749c81cc4396b2cc4,2675
|
||||||
|
- completed:
|
||||||
|
hackage: hasql-implicits-0.1.0.4@sha256:0848d3cbc9d94e1e539948fa0be4d0326b26335034161bf8076785293444ca6f,1361
|
||||||
|
pantry-tree:
|
||||||
|
size: 264
|
||||||
|
sha256: d49af8f8749ab7039fa668af4b78f997f7fa2928b4aded6798f573a3d08e76a0
|
||||||
|
original:
|
||||||
|
hackage: hasql-implicits-0.1.0.4@sha256:0848d3cbc9d94e1e539948fa0be4d0326b26335034161bf8076785293444ca6f,1361
|
||||||
|
- completed:
|
||||||
|
hackage: hasql-pool-0.5.2.2@sha256:b56d4dea112d97a2ef4b2749508c0ca646828cb2d77b827e8dc433d249bb2062,2438
|
||||||
|
pantry-tree:
|
||||||
|
size: 412
|
||||||
|
sha256: 2741a33f947d28b4076c798c20c1f646beecd21f5eaf522c8256cbeb34d4d6d0
|
||||||
|
original:
|
||||||
|
hackage: hasql-pool-0.5.2.2@sha256:b56d4dea112d97a2ef4b2749508c0ca646828cb2d77b827e8dc433d249bb2062,2438
|
||||||
|
- completed:
|
||||||
|
hackage: lens-aeson-1.1.3@sha256:52c8eaecd2d1c2a969c0762277c4a8ee72c339a686727d5785932e72ef9c3050,1764
|
||||||
|
pantry-tree:
|
||||||
|
size: 541
|
||||||
|
sha256: b31392b78f2a03111c805f4400007778eb93b49f998ab41dfbebaaf9b5526bad
|
||||||
|
original:
|
||||||
|
hackage: lens-aeson-1.1.3@sha256:52c8eaecd2d1c2a969c0762277c4a8ee72c339a686727d5785932e72ef9c3050,1764
|
||||||
|
- completed:
|
||||||
|
hackage: optparse-applicative-0.16.1.0@sha256:418c22ed6a19124d457d96bc66bd22c93ac22fad0c7100fe4972bbb4ac989731,4982
|
||||||
|
pantry-tree:
|
||||||
|
size: 2979
|
||||||
|
sha256: dd092d843091c08691485d68a1908517079b1bc6f3d73928f37635a19dc27fc1
|
||||||
|
original:
|
||||||
|
hackage: optparse-applicative-0.16.1.0@sha256:418c22ed6a19124d457d96bc66bd22c93ac22fad0c7100fe4972bbb4ac989731,4982
|
||||||
|
- completed:
|
||||||
|
hackage: protolude-0.3.2@sha256:2a38b3dad40d238ab644e234b692c8911423f9d3ed0e36b62287c4a698d92cd1,2240
|
||||||
|
pantry-tree:
|
||||||
|
size: 1594
|
||||||
|
sha256: a36d2912ac552d950ba4476de7d950b56b82dd28e48b9f4d0efee938f10bc525
|
||||||
|
original:
|
||||||
|
hackage: protolude-0.3.2@sha256:2a38b3dad40d238ab644e234b692c8911423f9d3ed0e36b62287c4a698d92cd1,2240
|
||||||
|
- completed:
|
||||||
|
hackage: ptr-0.16.8.2@sha256:708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac,3959
|
||||||
|
pantry-tree:
|
||||||
|
size: 1303
|
||||||
|
sha256: 557c438345de19f82bf01d676100da2a191ef06f624e7a4b90b09ac17cbb52a5
|
||||||
|
original:
|
||||||
|
hackage: ptr-0.16.8.2@sha256:708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac,3959
|
||||||
|
snapshots:
|
||||||
|
- completed:
|
||||||
|
size: 618951
|
||||||
|
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/14.yaml
|
||||||
|
sha256: 4c31d4ef975b0211078862566aedf3b82b6cea569fc2cde4c72a51e5a8d236ce
|
||||||
|
original: lts-19.14
|
||||||
Loading…
x
Reference in New Issue
Block a user