-
Notifications
You must be signed in to change notification settings - Fork 577
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add cataloger for Swift Package Manager.
Signed-off-by: Tristan Farkas <[email protected]>
- Loading branch information
Tristan Farkas
authored and
Tristan Farkas
committed
Jul 7, 2023
1 parent
376c428
commit 74ba142
Showing
21 changed files
with
481 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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/[email protected]", | ||
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/[email protected]", | ||
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/[email protected]", | ||
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/[email protected]", | ||
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/[email protected]", | ||
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) | ||
} |
Oops, something went wrong.