mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
Add cataloger for Swift Package Manager. (#1919)
Signed-off-by: Tristan Farkas <Tristan.Farkas@axis.com>
This commit is contained in:
parent
9a73380f29
commit
e1c1832f84
24 changed files with 2353 additions and 14 deletions
|
@ -5,3 +5,7 @@ The following Syft components were contributed by external authors/organizations
|
||||||
## GraalVM Native Image
|
## GraalVM Native Image
|
||||||
|
|
||||||
A cataloger contributed by Oracle Corporation that extracts packages given within GraalVM Native Image SBOMs.
|
A cataloger contributed by Oracle Corporation that extracts packages given within GraalVM Native Image SBOMs.
|
||||||
|
|
||||||
|
## Swift Package Manager
|
||||||
|
|
||||||
|
A cataloger contributed by Axis Communications that catalogs packages resolved by Swift Package Manager.
|
|
@ -53,7 +53,7 @@ For commercial support options with Syft or Grype, please [contact Anchore](http
|
||||||
- Red Hat (rpm)
|
- Red Hat (rpm)
|
||||||
- Ruby (gem)
|
- Ruby (gem)
|
||||||
- Rust (cargo.lock)
|
- Rust (cargo.lock)
|
||||||
- Swift (cocoapods)
|
- Swift (cocoapods, swift-package-manager)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
@ -211,6 +211,7 @@ You can override the list of enabled/disabled catalogers by using the "cataloger
|
||||||
- ruby-gemfile
|
- ruby-gemfile
|
||||||
- rust-cargo-lock
|
- rust-cargo-lock
|
||||||
- sbom
|
- sbom
|
||||||
|
- swift-package-manager
|
||||||
|
|
||||||
##### Non Default:
|
##### Non Default:
|
||||||
- cargo-auditable-binary
|
- cargo-auditable-binary
|
||||||
|
@ -521,6 +522,7 @@ platform: ""
|
||||||
# - ruby-gemspec-cataloger
|
# - ruby-gemspec-cataloger
|
||||||
# - rust-cargo-lock-cataloger
|
# - rust-cargo-lock-cataloger
|
||||||
# - sbom-cataloger
|
# - sbom-cataloger
|
||||||
|
# - spm-cataloger
|
||||||
catalogers:
|
catalogers:
|
||||||
|
|
||||||
# cataloging packages is exposed through the packages and power-user subcommands
|
# cataloging packages is exposed through the packages and power-user subcommands
|
||||||
|
|
|
@ -6,5 +6,5 @@ const (
|
||||||
|
|
||||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||||
JSONSchemaVersion = "9.0.1"
|
JSONSchemaVersion = "9.0.2"
|
||||||
)
|
)
|
||||||
|
|
1931
schema/json/schema-9.0.2.json
Normal file
1931
schema/json/schema-9.0.2.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -54,6 +54,8 @@ func SourceInfo(p pkg.Package) string {
|
||||||
answer = "acquired package info from nix store path"
|
answer = "acquired package info from nix store path"
|
||||||
case pkg.Rpkg:
|
case pkg.Rpkg:
|
||||||
answer = "acquired package info from R-package DESCRIPTION file"
|
answer = "acquired package info from R-package DESCRIPTION file"
|
||||||
|
case pkg.SwiftPkg:
|
||||||
|
answer = "acquired package info from resolved Swift package manifest"
|
||||||
default:
|
default:
|
||||||
answer = "acquired package info from the following paths"
|
answer = "acquired package info from the following paths"
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,6 +231,14 @@ func Test_SourceInfo(t *testing.T) {
|
||||||
"acquired package info from R-package DESCRIPTION file",
|
"acquired package info from R-package DESCRIPTION file",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: pkg.Package{
|
||||||
|
Type: pkg.SwiftPkg,
|
||||||
|
},
|
||||||
|
expected: []string{
|
||||||
|
"from resolved Swift package manifest",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
var pkgTypes []pkg.Type
|
var pkgTypes []pkg.Type
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
|
@ -6,5 +6,5 @@ import "github.com/anchore/syft/syft/pkg"
|
||||||
|
|
||||||
// AllTypes returns a list of all pkg metadata types that syft supports (that are represented in the pkg.Package.Metadata field).
|
// AllTypes returns a list of all pkg metadata types that syft supports (that are represented in the pkg.Package.Metadata field).
|
||||||
func AllTypes() []any {
|
func AllTypes() []any {
|
||||||
return []any{pkg.AlpmMetadata{}, pkg.ApkMetadata{}, pkg.BinaryMetadata{}, pkg.CargoPackageMetadata{}, pkg.CocoapodsMetadata{}, pkg.ConanLockMetadata{}, pkg.ConanMetadata{}, pkg.DartPubMetadata{}, pkg.DotnetDepsMetadata{}, pkg.DotnetPortableExecutableMetadata{}, pkg.DpkgMetadata{}, pkg.GemMetadata{}, pkg.GolangBinMetadata{}, pkg.GolangModMetadata{}, pkg.HackageMetadata{}, pkg.JavaMetadata{}, pkg.KbPackageMetadata{}, pkg.LinuxKernelMetadata{}, pkg.LinuxKernelModuleMetadata{}, pkg.MixLockMetadata{}, pkg.NixStoreMetadata{}, pkg.NpmPackageJSONMetadata{}, pkg.NpmPackageLockJSONMetadata{}, pkg.PhpComposerJSONMetadata{}, pkg.PortageMetadata{}, pkg.PythonPackageMetadata{}, pkg.PythonPipfileLockMetadata{}, pkg.PythonRequirementsMetadata{}, pkg.RDescriptionFileMetadata{}, pkg.RebarLockMetadata{}, pkg.RpmMetadata{}}
|
return []any{pkg.AlpmMetadata{}, pkg.ApkMetadata{}, pkg.BinaryMetadata{}, pkg.CargoPackageMetadata{}, pkg.CocoapodsMetadata{}, pkg.ConanLockMetadata{}, pkg.ConanMetadata{}, pkg.DartPubMetadata{}, pkg.DotnetDepsMetadata{}, pkg.DotnetPortableExecutableMetadata{}, pkg.DpkgMetadata{}, pkg.GemMetadata{}, pkg.GolangBinMetadata{}, pkg.GolangModMetadata{}, pkg.HackageMetadata{}, pkg.JavaMetadata{}, pkg.KbPackageMetadata{}, pkg.LinuxKernelMetadata{}, pkg.LinuxKernelModuleMetadata{}, pkg.MixLockMetadata{}, pkg.NixStoreMetadata{}, pkg.NpmPackageJSONMetadata{}, pkg.NpmPackageLockJSONMetadata{}, pkg.PhpComposerJSONMetadata{}, pkg.PortageMetadata{}, pkg.PythonPackageMetadata{}, pkg.PythonPipfileLockMetadata{}, pkg.PythonRequirementsMetadata{}, pkg.RDescriptionFileMetadata{}, pkg.RebarLockMetadata{}, pkg.RpmMetadata{}, pkg.SwiftPackageManagerMetadata{}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
|
||||||
rust.NewCargoLockCataloger(),
|
rust.NewCargoLockCataloger(),
|
||||||
sbom.NewSBOMCataloger(),
|
sbom.NewSBOMCataloger(),
|
||||||
swift.NewCocoapodsCataloger(),
|
swift.NewCocoapodsCataloger(),
|
||||||
|
swift.NewSwiftPackageManagerCataloger(),
|
||||||
}, cfg.Catalogers)
|
}, cfg.Catalogers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +135,7 @@ func AllCatalogers(cfg Config) []pkg.Cataloger {
|
||||||
rust.NewCargoLockCataloger(),
|
rust.NewCargoLockCataloger(),
|
||||||
sbom.NewSBOMCataloger(),
|
sbom.NewSBOMCataloger(),
|
||||||
swift.NewCocoapodsCataloger(),
|
swift.NewCocoapodsCataloger(),
|
||||||
|
swift.NewSwiftPackageManagerCataloger(),
|
||||||
}, cfg.Catalogers)
|
}, cfg.Catalogers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Package swift provides a concrete Cataloger implementation for Podfile.lock files.
|
Package swift provides a concrete Cataloger implementation for Podfile.lock and Package.resolved files.
|
||||||
*/
|
*/
|
||||||
package swift
|
package swift
|
||||||
|
|
||||||
|
@ -7,6 +7,11 @@ import (
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewSwiftPackageManagerCataloger() *generic.Cataloger {
|
||||||
|
return generic.NewCataloger("spm-cataloger").
|
||||||
|
WithParserByGlobs(parsePackageResolved, "**/Package.resolved", "**/.package.resolved")
|
||||||
|
}
|
||||||
|
|
||||||
// NewCocoapodsCataloger returns a new Swift Cocoapods lock file cataloger object.
|
// NewCocoapodsCataloger returns a new Swift Cocoapods lock file cataloger object.
|
||||||
func NewCocoapodsCataloger() *generic.Cataloger {
|
func NewCocoapodsCataloger() *generic.Cataloger {
|
||||||
return generic.NewCataloger("cocoapods-cataloger").
|
return generic.NewCataloger("cocoapods-cataloger").
|
||||||
|
|
|
@ -1,16 +1,37 @@
|
||||||
package swift
|
package swift
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/anchore/packageurl-go"
|
"github.com/anchore/packageurl-go"
|
||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newPackage(name, version, hash string, locations ...file.Location) pkg.Package {
|
func newSwiftPackageManagerPackage(name, version, sourceURL, revision string, locations ...file.Location) pkg.Package {
|
||||||
p := pkg.Package{
|
p := pkg.Package{
|
||||||
Name: name,
|
Name: name,
|
||||||
Version: version,
|
Version: version,
|
||||||
PURL: packageURL(name, version),
|
PURL: swiftPackageManagerPackageURL(name, version, sourceURL),
|
||||||
|
Locations: file.NewLocationSet(locations...),
|
||||||
|
Type: pkg.SwiftPkg,
|
||||||
|
Language: pkg.Swift,
|
||||||
|
MetadataType: pkg.SwiftPackageManagerMetadataType,
|
||||||
|
Metadata: pkg.SwiftPackageManagerMetadata{
|
||||||
|
Revision: revision,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetID()
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCocoaPodsPackage(name, version, hash string, locations ...file.Location) pkg.Package {
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: name,
|
||||||
|
Version: version,
|
||||||
|
PURL: cocoaPodsPackageURL(name, version),
|
||||||
Locations: file.NewLocationSet(locations...),
|
Locations: file.NewLocationSet(locations...),
|
||||||
Type: pkg.CocoapodsPkg,
|
Type: pkg.CocoapodsPkg,
|
||||||
Language: pkg.Swift,
|
Language: pkg.Swift,
|
||||||
|
@ -25,7 +46,7 @@ func newPackage(name, version, hash string, locations ...file.Location) pkg.Pack
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func packageURL(name, version string) string {
|
func cocoaPodsPackageURL(name, version string) string {
|
||||||
var qualifiers packageurl.Qualifiers
|
var qualifiers packageurl.Qualifiers
|
||||||
|
|
||||||
return packageurl.NewPackageURL(
|
return packageurl.NewPackageURL(
|
||||||
|
@ -37,3 +58,16 @@ func packageURL(name, version string) string {
|
||||||
"",
|
"",
|
||||||
).ToString()
|
).ToString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func swiftPackageManagerPackageURL(name, version, sourceURL string) string {
|
||||||
|
var qualifiers packageurl.Qualifiers
|
||||||
|
|
||||||
|
return packageurl.NewPackageURL(
|
||||||
|
packageurl.TypeSwift,
|
||||||
|
strings.Replace(sourceURL, "https://", "", 1),
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
qualifiers,
|
||||||
|
"",
|
||||||
|
).ToString()
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_packageURL(t *testing.T) {
|
func Test_cocoaPodsPackageURL(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
name string
|
name string
|
||||||
version string
|
version string
|
||||||
|
@ -27,7 +27,7 @@ func Test_packageURL(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
assert.Equal(t, tt.want, packageURL(tt.args.name, tt.args.version))
|
assert.Equal(t, tt.want, cocoaPodsPackageURL(tt.args.name, tt.args.version))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
134
syft/pkg/cataloger/swift/parse_package_resolved.go
Normal file
134
syft/pkg/cataloger/swift/parse_package_resolved.go
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
package swift
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ generic.Parser = parsePackageResolved
|
||||||
|
|
||||||
|
// swift package manager has two versions (1 and 2) of the resolved files, the types below describes the serialization strategies for each version
|
||||||
|
// with its suffix indicating which version its specific to.
|
||||||
|
|
||||||
|
type packageResolvedV1 struct {
|
||||||
|
PackageObject packageObjectV1 `json:"object"`
|
||||||
|
Version int `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type packageObjectV1 struct {
|
||||||
|
Pins []packagePinsV1
|
||||||
|
}
|
||||||
|
|
||||||
|
type packagePinsV1 struct {
|
||||||
|
Name string `json:"package"`
|
||||||
|
RepositoryURL string `json:"repositoryURL"`
|
||||||
|
State packageState `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type packageResolvedV2 struct {
|
||||||
|
Pins []packagePinsV2
|
||||||
|
}
|
||||||
|
|
||||||
|
type packagePinsV2 struct {
|
||||||
|
Identity string `json:"identity"`
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
Location string `json:"location"`
|
||||||
|
State packageState `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type packagePin struct {
|
||||||
|
Identity string
|
||||||
|
Location string
|
||||||
|
Revision string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
type packageState struct {
|
||||||
|
Revision string `json:"revision"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsePackageResolved is a parser for the contents of a Package.resolved file, which is generated by Xcode after it's resolved Swift Package Manger packages.
|
||||||
|
func parsePackageResolved(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
dec := json.NewDecoder(reader)
|
||||||
|
var packageResolvedData map[string]interface{}
|
||||||
|
for {
|
||||||
|
if err := dec.Decode(&packageResolvedData); errors.Is(err, io.EOF) {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to parse Package.resolved file: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pins, err = pinsForVersion(packageResolvedData, packageResolvedData["version"].(float64))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkgs []pkg.Package
|
||||||
|
for _, packagePin := range pins {
|
||||||
|
pkgs = append(
|
||||||
|
pkgs,
|
||||||
|
newSwiftPackageManagerPackage(
|
||||||
|
packagePin.Identity,
|
||||||
|
packagePin.Version,
|
||||||
|
packagePin.Location,
|
||||||
|
packagePin.Revision,
|
||||||
|
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return pkgs, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func pinsForVersion(data map[string]interface{}, version float64) ([]packagePin, error) {
|
||||||
|
var genericPins []packagePin
|
||||||
|
switch version {
|
||||||
|
case 1:
|
||||||
|
t := packageResolvedV1{}
|
||||||
|
jsonString, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
parseErr := json.Unmarshal(jsonString, &t)
|
||||||
|
if parseErr != nil {
|
||||||
|
return nil, parseErr
|
||||||
|
}
|
||||||
|
for _, pin := range t.PackageObject.Pins {
|
||||||
|
genericPins = append(genericPins, packagePin{
|
||||||
|
pin.Name,
|
||||||
|
pin.RepositoryURL,
|
||||||
|
pin.State.Revision,
|
||||||
|
pin.State.Version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
t := packageResolvedV2{}
|
||||||
|
jsonString, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
parseErr := json.Unmarshal(jsonString, &t)
|
||||||
|
if parseErr != nil {
|
||||||
|
return nil, parseErr
|
||||||
|
}
|
||||||
|
for _, pin := range t.Pins {
|
||||||
|
genericPins = append(genericPins, packagePin{
|
||||||
|
pin.Identity,
|
||||||
|
pin.Location,
|
||||||
|
pin.State.Revision,
|
||||||
|
pin.State.Version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown swift package manager version, %f", version)
|
||||||
|
}
|
||||||
|
return genericPins, nil
|
||||||
|
}
|
82
syft/pkg/cataloger/swift/parse_package_resolved_test.go
Normal file
82
syft/pkg/cataloger/swift/parse_package_resolved_test.go
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package swift
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParsePackageResolved(t *testing.T) {
|
||||||
|
fixture := "test-fixtures/Package.resolved"
|
||||||
|
locations := file.NewLocationSet(file.NewLocation(fixture))
|
||||||
|
expectedPkgs := []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "swift-algorithms",
|
||||||
|
Version: "1.0.0",
|
||||||
|
PURL: "pkg:swift/github.com/apple/swift-algorithms.git/swift-algorithms@1.0.0",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Swift,
|
||||||
|
Type: pkg.SwiftPkg,
|
||||||
|
MetadataType: pkg.SwiftPackageManagerMetadataType,
|
||||||
|
Metadata: pkg.SwiftPackageManagerMetadata{
|
||||||
|
Revision: "b14b7f4c528c942f121c8b860b9410b2bf57825e",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "swift-async-algorithms",
|
||||||
|
Version: "0.1.0",
|
||||||
|
PURL: "pkg:swift/github.com/apple/swift-async-algorithms.git/swift-async-algorithms@0.1.0",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Swift,
|
||||||
|
Type: pkg.SwiftPkg,
|
||||||
|
MetadataType: pkg.SwiftPackageManagerMetadataType,
|
||||||
|
Metadata: pkg.SwiftPackageManagerMetadata{
|
||||||
|
Revision: "9cfed92b026c524674ed869a4ff2dcfdeedf8a2a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "swift-atomics",
|
||||||
|
Version: "1.1.0",
|
||||||
|
PURL: "pkg:swift/github.com/apple/swift-atomics.git/swift-atomics@1.1.0",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Swift,
|
||||||
|
Type: pkg.SwiftPkg,
|
||||||
|
MetadataType: pkg.SwiftPackageManagerMetadataType,
|
||||||
|
Metadata: pkg.SwiftPackageManagerMetadata{
|
||||||
|
Revision: "6c89474e62719ddcc1e9614989fff2f68208fe10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "swift-collections",
|
||||||
|
Version: "1.0.4",
|
||||||
|
PURL: "pkg:swift/github.com/apple/swift-collections.git/swift-collections@1.0.4",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Swift,
|
||||||
|
Type: pkg.SwiftPkg,
|
||||||
|
MetadataType: pkg.SwiftPackageManagerMetadataType,
|
||||||
|
Metadata: pkg.SwiftPackageManagerMetadata{
|
||||||
|
Revision: "937e904258d22af6e447a0b72c0bc67583ef64a2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "swift-numerics",
|
||||||
|
Version: "1.0.2",
|
||||||
|
PURL: "pkg:swift/github.com/apple/swift-numerics/swift-numerics@1.0.2",
|
||||||
|
Locations: locations,
|
||||||
|
Language: pkg.Swift,
|
||||||
|
Type: pkg.SwiftPkg,
|
||||||
|
MetadataType: pkg.SwiftPackageManagerMetadataType,
|
||||||
|
Metadata: pkg.SwiftPackageManagerMetadata{
|
||||||
|
Revision: "0a5bc04095a675662cf24757cc0640aa2204253b",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: no relationships are under test yet
|
||||||
|
var expectedRelationships []artifact.Relationship
|
||||||
|
|
||||||
|
pkgtest.TestFileParser(t, fixture, parsePackageResolved, expectedPkgs, expectedRelationships)
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ func parsePodfileLock(_ file.Resolver, _ *generic.Environment, reader file.Locat
|
||||||
|
|
||||||
pkgs = append(
|
pkgs = append(
|
||||||
pkgs,
|
pkgs,
|
||||||
newPackage(
|
newCocoaPodsPackage(
|
||||||
podName,
|
podName,
|
||||||
podVersion,
|
podVersion,
|
||||||
pkgHash,
|
pkgHash,
|
||||||
|
|
50
syft/pkg/cataloger/swift/test-fixtures/Package.resolved
Normal file
50
syft/pkg/cataloger/swift/test-fixtures/Package.resolved
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "swift-algorithms",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-algorithms.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "b14b7f4c528c942f121c8b860b9410b2bf57825e",
|
||||||
|
"version" : "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-async-algorithms",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-async-algorithms.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "9cfed92b026c524674ed869a4ff2dcfdeedf8a2a",
|
||||||
|
"version" : "0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-atomics",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-atomics.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10",
|
||||||
|
"version" : "1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-collections",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-collections.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2",
|
||||||
|
"version" : "1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-numerics",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-numerics",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "0a5bc04095a675662cf24757cc0640aa2204253b",
|
||||||
|
"version" : "1.0.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
|
@ -82,7 +82,7 @@ func LanguageByName(name string) Language {
|
||||||
return Dart
|
return Dart
|
||||||
case packageurl.TypeDotnet:
|
case packageurl.TypeDotnet:
|
||||||
return Dotnet
|
return Dotnet
|
||||||
case packageurl.TypeCocoapods, packageurl.TypeSwift, string(CocoapodsPkg):
|
case packageurl.TypeCocoapods, packageurl.TypeSwift, string(CocoapodsPkg), string(SwiftPkg):
|
||||||
return Swift
|
return Swift
|
||||||
case packageurl.TypeConan, string(CPP):
|
case packageurl.TypeConan, string(CPP):
|
||||||
return CPP
|
return CPP
|
||||||
|
|
|
@ -70,9 +70,13 @@ func TestLanguageFromPURL(t *testing.T) {
|
||||||
purl: "pkg:cran/base@4.3.0",
|
purl: "pkg:cran/base@4.3.0",
|
||||||
want: R,
|
want: R,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
purl: "pkg:swift/github.com/apple/swift-numerics/swift-numerics@1.0.2",
|
||||||
|
want: Swift,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var languages []string
|
var languages = strset.New()
|
||||||
var expectedLanguages = strset.New()
|
var expectedLanguages = strset.New()
|
||||||
for _, ty := range AllLanguages {
|
for _, ty := range AllLanguages {
|
||||||
expectedLanguages.Add(string(ty))
|
expectedLanguages.Add(string(ty))
|
||||||
|
@ -87,14 +91,14 @@ func TestLanguageFromPURL(t *testing.T) {
|
||||||
actual := LanguageFromPURL(tt.purl)
|
actual := LanguageFromPURL(tt.purl)
|
||||||
|
|
||||||
if actual != "" {
|
if actual != "" {
|
||||||
languages = append(languages, string(actual))
|
languages.Add(string(actual))
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equalf(t, tt.want, actual, "LanguageFromPURL(%v)", tt.purl)
|
assert.Equalf(t, tt.want, actual, "LanguageFromPURL(%v)", tt.purl)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.ElementsMatch(t, expectedLanguages.List(), languages, "missing one or more languages to test against (maybe a package type was added?)")
|
assert.ElementsMatch(t, expectedLanguages.List(), languages.List(), "missing one or more languages to test against (maybe a package type was added?)")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ const (
|
||||||
RDescriptionFileMetadataType MetadataType = "RDescriptionFileMetadataType"
|
RDescriptionFileMetadataType MetadataType = "RDescriptionFileMetadataType"
|
||||||
RpmMetadataType MetadataType = "RpmMetadata"
|
RpmMetadataType MetadataType = "RpmMetadata"
|
||||||
RustCargoPackageMetadataType MetadataType = "RustCargoPackageMetadata"
|
RustCargoPackageMetadataType MetadataType = "RustCargoPackageMetadata"
|
||||||
|
SwiftPackageManagerMetadataType MetadataType = "SwiftPackageManagerMetadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
var AllMetadataTypes = []MetadataType{
|
var AllMetadataTypes = []MetadataType{
|
||||||
|
@ -76,6 +77,7 @@ var AllMetadataTypes = []MetadataType{
|
||||||
RebarLockMetadataType,
|
RebarLockMetadataType,
|
||||||
RpmMetadataType,
|
RpmMetadataType,
|
||||||
RustCargoPackageMetadataType,
|
RustCargoPackageMetadataType,
|
||||||
|
SwiftPackageManagerMetadataType,
|
||||||
}
|
}
|
||||||
|
|
||||||
var MetadataTypeByName = map[MetadataType]reflect.Type{
|
var MetadataTypeByName = map[MetadataType]reflect.Type{
|
||||||
|
@ -110,6 +112,7 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{
|
||||||
RebarLockMetadataType: reflect.TypeOf(RebarLockMetadata{}),
|
RebarLockMetadataType: reflect.TypeOf(RebarLockMetadata{}),
|
||||||
RpmMetadataType: reflect.TypeOf(RpmMetadata{}),
|
RpmMetadataType: reflect.TypeOf(RpmMetadata{}),
|
||||||
RustCargoPackageMetadataType: reflect.TypeOf(CargoPackageMetadata{}),
|
RustCargoPackageMetadataType: reflect.TypeOf(CargoPackageMetadata{}),
|
||||||
|
SwiftPackageManagerMetadataType: reflect.TypeOf(SwiftPackageManagerMetadata{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
func CleanMetadataType(typ MetadataType) MetadataType {
|
func CleanMetadataType(typ MetadataType) MetadataType {
|
||||||
|
|
5
syft/pkg/swiftpackagemanager_metadata.go
Normal file
5
syft/pkg/swiftpackagemanager_metadata.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package pkg
|
||||||
|
|
||||||
|
type SwiftPackageManagerMetadata struct {
|
||||||
|
Revision string `mapstructure:"revision" json:"revision"`
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ const (
|
||||||
Rpkg Type = "R-package"
|
Rpkg Type = "R-package"
|
||||||
RpmPkg Type = "rpm"
|
RpmPkg Type = "rpm"
|
||||||
RustPkg Type = "rust-crate"
|
RustPkg Type = "rust-crate"
|
||||||
|
SwiftPkg Type = "swift"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllPkgs represents all supported package types
|
// AllPkgs represents all supported package types
|
||||||
|
@ -65,6 +66,7 @@ var AllPkgs = []Type{
|
||||||
Rpkg,
|
Rpkg,
|
||||||
RpmPkg,
|
RpmPkg,
|
||||||
RustPkg,
|
RustPkg,
|
||||||
|
SwiftPkg,
|
||||||
}
|
}
|
||||||
|
|
||||||
// PackageURLType returns the PURL package type for the current package.
|
// PackageURLType returns the PURL package type for the current package.
|
||||||
|
@ -114,6 +116,8 @@ func (t Type) PackageURLType() string {
|
||||||
return packageurl.TypeRPM
|
return packageurl.TypeRPM
|
||||||
case RustPkg:
|
case RustPkg:
|
||||||
return "cargo"
|
return "cargo"
|
||||||
|
case SwiftPkg:
|
||||||
|
return packageurl.TypeSwift
|
||||||
default:
|
default:
|
||||||
// TODO: should this be a "generic" purl type instead?
|
// TODO: should this be a "generic" purl type instead?
|
||||||
return ""
|
return ""
|
||||||
|
@ -179,6 +183,8 @@ func TypeByName(name string) Type {
|
||||||
return NixPkg
|
return NixPkg
|
||||||
case packageurl.TypeCran:
|
case packageurl.TypeCran:
|
||||||
return Rpkg
|
return Rpkg
|
||||||
|
case packageurl.TypeSwift:
|
||||||
|
return SwiftPkg
|
||||||
default:
|
default:
|
||||||
return UnknownPkg
|
return UnknownPkg
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,10 @@ func TestTypeFromPURL(t *testing.T) {
|
||||||
purl: "pkg:cran/base@4.3.0",
|
purl: "pkg:cran/base@4.3.0",
|
||||||
expected: Rpkg,
|
expected: Rpkg,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
purl: "pkg:swift/github.com/apple/swift-numerics/swift-numerics@1.0.2",
|
||||||
|
expected: SwiftPkg,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var pkgTypes []string
|
var pkgTypes []string
|
||||||
|
|
|
@ -356,6 +356,18 @@ var dirOnlyTestCases = []testCase{
|
||||||
"unicode_util_compat": "0.7.0",
|
"unicode_util_compat": "0.7.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "find swift package manager packages",
|
||||||
|
pkgType: pkg.SwiftPkg,
|
||||||
|
pkgLanguage: pkg.Swift,
|
||||||
|
pkgInfo: map[string]string{
|
||||||
|
"swift-algorithms": "1.0.0",
|
||||||
|
"swift-async-algorithms": "0.1.0",
|
||||||
|
"swift-atomics": "1.1.0",
|
||||||
|
"swift-collections": "1.0.4",
|
||||||
|
"swift-numerics": "1.0.2",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var commonTestCases = []testCase{
|
var commonTestCases = []testCase{
|
||||||
|
|
|
@ -95,6 +95,7 @@ func TestPkgCoverageImage(t *testing.T) {
|
||||||
definedPkgs.Remove(string(pkg.HexPkg))
|
definedPkgs.Remove(string(pkg.HexPkg))
|
||||||
definedPkgs.Remove(string(pkg.LinuxKernelPkg))
|
definedPkgs.Remove(string(pkg.LinuxKernelPkg))
|
||||||
definedPkgs.Remove(string(pkg.LinuxKernelModulePkg))
|
definedPkgs.Remove(string(pkg.LinuxKernelModulePkg))
|
||||||
|
definedPkgs.Remove(string(pkg.SwiftPkg))
|
||||||
|
|
||||||
var cases []testCase
|
var cases []testCase
|
||||||
cases = append(cases, commonTestCases...)
|
cases = append(cases, commonTestCases...)
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "swift-algorithms",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-algorithms.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "b14b7f4c528c942f121c8b860b9410b2bf57825e",
|
||||||
|
"version" : "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-async-algorithms",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-async-algorithms.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "9cfed92b026c524674ed869a4ff2dcfdeedf8a2a",
|
||||||
|
"version" : "0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-atomics",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-atomics.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10",
|
||||||
|
"version" : "1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-collections",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-collections.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2",
|
||||||
|
"version" : "1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-numerics",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-numerics",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "0a5bc04095a675662cf24757cc0640aa2204253b",
|
||||||
|
"version" : "1.0.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
Loading…
Reference in a new issue