mirror of
https://github.com/anchore/syft.git
synced 2026-10-28 04:52:23 +01:00
Compare commits
@@ -14,4 +14,4 @@ jobs:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/anchore/projects/22
|
||||
github-token: ${{ secrets.CI_WRITE_GITHUB_TOKEN }}
|
||||
github-token: ${{ secrets.ANCHORE_TOOLS_OPS_TEST }}
|
||||
@@ -30,9 +30,12 @@ A CLI tool and Go library for generating a Software Bill of Materials (SBOM) fro
|
||||
### Supported Ecosystems
|
||||
|
||||
- Alpine (apk)
|
||||
- C (conan)
|
||||
- C++ (conan)
|
||||
- Dart (pubs)
|
||||
- Debian (dpkg)
|
||||
- Dotnet (deps.json)
|
||||
- Objective-C (cocoapods)
|
||||
- Go (go.mod, Go binaries)
|
||||
- Java (jar, ear, war, par, sar)
|
||||
- JavaScript (npm, yarn)
|
||||
@@ -42,6 +45,7 @@ A CLI tool and Go library for generating a Software Bill of Materials (SBOM) fro
|
||||
- Red Hat (rpm)
|
||||
- Ruby (gem)
|
||||
- Rust (cargo.lock)
|
||||
- Swift (cocoapods)
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ func Run(ctx context.Context, app *config.Application, ko sigopts.KeyOpts, args
|
||||
subscription := eventBus.Subscribe()
|
||||
|
||||
return eventloop.EventLoop(
|
||||
execWorker(app, *si, format, predicateType, sv),
|
||||
execWorker(app, *si, format, predicateType, sv, app.File),
|
||||
eventloop.SetupSignals(),
|
||||
subscription,
|
||||
stereoscope.Cleanup,
|
||||
@@ -137,7 +137,7 @@ func parseImageSource(userInput string, app *config.Application) (s *source.Inpu
|
||||
return si, nil
|
||||
}
|
||||
|
||||
func execWorker(app *config.Application, sourceInput source.Input, format sbom.Format, predicateType string, sv *sign.SignerVerifier) <-chan error {
|
||||
func execWorker(app *config.Application, sourceInput source.Input, format sbom.Format, predicateType string, sv *sign.SignerVerifier, file string) <-chan error {
|
||||
errs := make(chan error)
|
||||
go func() {
|
||||
defer close(errs)
|
||||
@@ -163,7 +163,7 @@ func execWorker(app *config.Application, sourceInput source.Input, format sbom.F
|
||||
return
|
||||
}
|
||||
|
||||
err = generateAttestation(app, sbomBytes, src, sv, predicateType)
|
||||
err = generateAttestation(app, sbomBytes, src, sv, predicateType, file)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
@@ -172,7 +172,7 @@ func execWorker(app *config.Application, sourceInput source.Input, format sbom.F
|
||||
return errs
|
||||
}
|
||||
|
||||
func generateAttestation(app *config.Application, predicate []byte, src *source.Source, sv *sign.SignerVerifier, predicateType string) error {
|
||||
func generateAttestation(app *config.Application, predicate []byte, src *source.Source, sv *sign.SignerVerifier, predicateType string, file string) error {
|
||||
switch len(src.Image.Metadata.RepoDigests) {
|
||||
case 0:
|
||||
return fmt.Errorf("cannot generate attestation since no repo digests were found; make sure you're passing an OCI registry source for the attest command")
|
||||
@@ -219,7 +219,12 @@ func generateAttestation(app *config.Application, predicate []byte, src *source.
|
||||
bus.Publish(partybus.Event{
|
||||
Type: event.Exit,
|
||||
Value: func() error {
|
||||
_, err := os.Stdout.Write(signedPayload)
|
||||
var err error
|
||||
if file != "" {
|
||||
err = os.WriteFile(file, signedPayload, 0600)
|
||||
} else {
|
||||
_, err = os.Stdout.Write(signedPayload)
|
||||
}
|
||||
return err
|
||||
},
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
cranecmd "github.com/google/go-containerregistry/cmd/crane/cmd"
|
||||
"github.com/gookit/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -30,6 +31,7 @@ const indent = " "
|
||||
// at this level. Values from the config should only be used after `app.LoadAllValues` has been called.
|
||||
// Cobra does not have knowledge of the user provided flags until the `RunE` block of each command.
|
||||
// `RunE` is the earliest that the complete application configuration can be loaded.
|
||||
// nolint:funlen
|
||||
func New() (*cobra.Command, error) {
|
||||
app := &config.Application{}
|
||||
|
||||
@@ -82,13 +84,22 @@ func New() (*cobra.Command, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// commands to add to root
|
||||
cmds := []*cobra.Command{
|
||||
packagesCmd,
|
||||
attestCmd,
|
||||
convertCmd,
|
||||
poweruserCmd,
|
||||
poweruserCmd,
|
||||
Completion(),
|
||||
Version(v, app),
|
||||
cranecmd.NewCmdAuthLogin("syft"),
|
||||
}
|
||||
|
||||
// Add sub-commands.
|
||||
rootCmd.AddCommand(packagesCmd)
|
||||
rootCmd.AddCommand(attestCmd)
|
||||
rootCmd.AddCommand(convertCmd)
|
||||
rootCmd.AddCommand(poweruserCmd)
|
||||
rootCmd.AddCommand(Completion())
|
||||
rootCmd.AddCommand(Version(v, app))
|
||||
for _, cmd := range cmds {
|
||||
rootCmd.AddCommand(cmd)
|
||||
}
|
||||
|
||||
return rootCmd, err
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ require (
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7
|
||||
github.com/anchore/stereoscope v0.0.0-20220616165231-b0fd10fdee06
|
||||
github.com/anchore/stereoscope v0.0.0-20220708133445-777471f38c5b
|
||||
github.com/antihax/optional v1.0.0
|
||||
github.com/bmatcuk/doublestar/v4 v4.0.2
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
@@ -63,6 +63,7 @@ require (
|
||||
github.com/sigstore/rekor v0.4.1-0.20220114213500-23f583409af3
|
||||
github.com/sigstore/sigstore v1.2.1-0.20220424143412-3d41663116d5
|
||||
github.com/vbatts/go-mtree v0.5.0
|
||||
gopkg.in/yaml.v3 v3.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -102,7 +103,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.10.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.15.0 // indirect
|
||||
github.com/aws/smithy-go v1.11.2 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220517224237-e6f29200ae04 // indirect
|
||||
github.com/benbjohnson/clock v1.1.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
@@ -294,7 +295,6 @@ require (
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0 // indirect
|
||||
k8s.io/api v0.23.5 // indirect
|
||||
k8s.io/apimachinery v0.23.5 // indirect
|
||||
k8s.io/client-go v0.23.5 // indirect
|
||||
|
||||
@@ -184,6 +184,7 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
|
||||
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo=
|
||||
github.com/GoogleCloudPlatform/cloudsql-proxy v1.27.0/go.mod h1:bn9iHmAjogMoIPkqBGyJ9R1m9cXGCjBE/cuhBs3oEsQ=
|
||||
github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
@@ -273,8 +274,8 @@ github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZV
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7 h1:kDrYkTSM9uIxaX/P9s0F4nKYNM+hnSgLJdLpqvsaQ/g=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
|
||||
github.com/anchore/stereoscope v0.0.0-20220616165231-b0fd10fdee06 h1:TSRA7gtuia3eyleTO3t7iPU+9xHbdSaufoUFNQUwUXo=
|
||||
github.com/anchore/stereoscope v0.0.0-20220616165231-b0fd10fdee06/go.mod h1:sai2ZjAtT/y1GRQBDRbynhdhnQcGWBvVcv8CN3hTWmI=
|
||||
github.com/anchore/stereoscope v0.0.0-20220708133445-777471f38c5b h1:cDOGZbZYFNidVKJ0eO+pC3B0o23O95bXLyAck5fLiNE=
|
||||
github.com/anchore/stereoscope v0.0.0-20220708133445-777471f38c5b/go.mod h1:31d7mF3OgaWrCU8zVJTttBxaz57nP0tCPgKCCKcS5q8=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
@@ -392,8 +393,8 @@ github.com/aws/smithy-go v1.9.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAm
|
||||
github.com/aws/smithy-go v1.11.0/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
|
||||
github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE=
|
||||
github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795 h1:IWeCJzU+IYaO2rVEBlGPTBfe90cmGXFTLdhUFlzDGsY=
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795/go.mod h1:8vJsEZ4iRqG+Vx6pKhWK6U00qcj0KC37IsfszMkY6UE=
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220517224237-e6f29200ae04 h1:p2I85zYI9z5/c/3Q0LiO3RtNXcmXHTtJfml/hV16zNg=
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220517224237-e6f29200ae04/go.mod h1:Z+bXnIbhKJYSvxNwsNnwde7pDKxuqlEZCbUBoTwAqf0=
|
||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||
|
||||
@@ -30,7 +30,7 @@ func (cfg registry) loadDefaultValues(v *viper.Viper) {
|
||||
v.SetDefault("registry.auth", []RegistryCredentials{})
|
||||
}
|
||||
|
||||
// nolint: unparam
|
||||
// nolint:unparam
|
||||
func (cfg *registry) parseConfigValues() error {
|
||||
// there may be additional credentials provided by env var that should be appended to the set of credentials
|
||||
authority, username, password, token :=
|
||||
|
||||
@@ -6,5 +6,5 @@ const (
|
||||
|
||||
// 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.
|
||||
JSONSchemaVersion = "3.3.0"
|
||||
JSONSchemaVersion = "3.3.1"
|
||||
)
|
||||
|
||||
@@ -35,6 +35,12 @@ func SourceInfo(p pkg.Package) string {
|
||||
answer = "acquired package info from rust cargo manifest"
|
||||
case pkg.PhpComposerPkg:
|
||||
answer = "acquired package info from PHP composer manifest"
|
||||
case pkg.CocoapodsPkg:
|
||||
answer = "acquired package info from installed cocoapods manifest file"
|
||||
case pkg.ConanPkg:
|
||||
answer = "acquired package info from conan manifest"
|
||||
case pkg.PortagePkg:
|
||||
answer = "acquired package info from portage DB"
|
||||
default:
|
||||
answer = "acquired package info from the following paths"
|
||||
}
|
||||
|
||||
@@ -150,6 +150,30 @@ func Test_SourceInfo(t *testing.T) {
|
||||
"from ALPM DB",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.CocoapodsPkg,
|
||||
},
|
||||
expected: []string{
|
||||
"installed cocoapods manifest file",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.ConanPkg,
|
||||
},
|
||||
expected: []string{
|
||||
"from conan manifest",
|
||||
},
|
||||
},
|
||||
{
|
||||
input: pkg.Package{
|
||||
Type: pkg.PortagePkg,
|
||||
},
|
||||
expected: []string{
|
||||
"from portage DB",
|
||||
},
|
||||
},
|
||||
}
|
||||
var pkgTypes []pkg.Type
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -63,7 +63,7 @@ func (p *Package) UnmarshalJSON(b []byte) error {
|
||||
return unpackMetadata(p, unpacker)
|
||||
}
|
||||
|
||||
// nolint:funlen
|
||||
// nolint:funlen,gocognit,gocyclo
|
||||
func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
|
||||
p.MetadataType = unpacker.MetadataType
|
||||
switch p.MetadataType {
|
||||
@@ -145,12 +145,30 @@ func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.CocoapodsMetadataType:
|
||||
var payload pkg.CocoapodsMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.ConanaMetadataType:
|
||||
var payload pkg.ConanMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.DotnetDepsMetadataType:
|
||||
var payload pkg.DotnetDepsMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.PortageMetadataType:
|
||||
var payload pkg.PortageMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
default:
|
||||
log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID)
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.3.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.0.json"
|
||||
"version": "3.3.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.3.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.0.json"
|
||||
"version": "3.3.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.3.0",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.0.json"
|
||||
"version": "3.3.1",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.3.1.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ Given a version number format `MODEL.REVISION.ADDITION`:
|
||||
When adding a new `pkg.*Metadata` that is assigned to the `pkg.Package.Metadata` struct field it is important that a few things
|
||||
are done:
|
||||
|
||||
- a new integration test case is added to `test/integration/pkg_cases_test.go` that exercises the new package type with the new metadata
|
||||
- a new integration test case is added to `test/integration/catalog_packages_cases_test.go` that exercises the new package type with the new metadata
|
||||
- the new metadata struct is added to the `artifactMetadataContainer` struct within `schema/json/generate.go`
|
||||
|
||||
## Generating a New Schema
|
||||
@@ -36,4 +36,4 @@ Create the new schema by running `cd schema/json && go run generate.go` (note yo
|
||||
- If there is an existing schema for the given version and the new schema matches the existing schema, no action is taken
|
||||
- If there is an existing schema for the given version and the new schema **does not** match the existing schema, an error is shown indicating to increment the version appropriately (see the "Versioning" section)
|
||||
|
||||
***Note: never delete a JSON schema and never change an existing JSON schema once it has been published in a release!*** Only add new schemas with a newly incremented version. All previous schema files must be stored in the `schema/json/` directory.
|
||||
***Note: never delete a JSON schema and never change an existing JSON schema once it has been published in a release!*** Only add new schemas with a newly incremented version. All previous schema files must be stored in the `schema/json/` directory.
|
||||
|
||||
+14
-13
@@ -27,19 +27,20 @@ can be extended to include specific package metadata struct shapes in the future
|
||||
// When a new package metadata definition is created it will need to be manually added here. The variable name does
|
||||
// not matter as long as it is exported.
|
||||
type artifactMetadataContainer struct {
|
||||
Apk pkg.ApkMetadata
|
||||
Alpm pkg.AlpmMetadata
|
||||
Dpkg pkg.DpkgMetadata
|
||||
Gem pkg.GemMetadata
|
||||
Java pkg.JavaMetadata
|
||||
Npm pkg.NpmPackageJSONMetadata
|
||||
Python pkg.PythonPackageMetadata
|
||||
Rpm pkg.RpmdbMetadata
|
||||
Cargo pkg.CargoPackageMetadata
|
||||
Go pkg.GolangBinMetadata
|
||||
Php pkg.PhpComposerJSONMetadata
|
||||
Dart pkg.DartPubMetadata
|
||||
Dotnet pkg.DotnetDepsMetadata
|
||||
Apk pkg.ApkMetadata
|
||||
Alpm pkg.AlpmMetadata
|
||||
Dpkg pkg.DpkgMetadata
|
||||
Gem pkg.GemMetadata
|
||||
Java pkg.JavaMetadata
|
||||
Npm pkg.NpmPackageJSONMetadata
|
||||
Python pkg.PythonPackageMetadata
|
||||
Rpm pkg.RpmdbMetadata
|
||||
Cargo pkg.CargoPackageMetadata
|
||||
Go pkg.GolangBinMetadata
|
||||
Php pkg.PhpComposerJSONMetadata
|
||||
Dart pkg.DartPubMetadata
|
||||
Dotnet pkg.DotnetDepsMetadata
|
||||
Portage pkg.PortageMetadata
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -64,6 +64,10 @@ func CatalogPackages(src *source.Source, cfg cataloger.Config) (*pkg.Catalog, []
|
||||
return nil, nil, nil, fmt.Errorf("unable to determine cataloger set from scheme=%+v", src.Metadata.Scheme)
|
||||
}
|
||||
|
||||
if cataloger.RequestedAllCatalogers(cfg) {
|
||||
catalogers = cataloger.AllCatalogers(cfg)
|
||||
}
|
||||
|
||||
catalog, relationships, err := cataloger.Catalog(resolver, release, catalogers...)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/alpm"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/apkdb"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/cpp"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/dart"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/deb"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/dotnet"
|
||||
@@ -20,13 +21,17 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/php"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/portage"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/python"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/rpmdb"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/ruby"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/rust"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/swift"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
const AllCatalogersPattern = "all"
|
||||
|
||||
// Cataloger describes behavior for an object to participate in parsing container image or file system
|
||||
// contents for the purpose of discovering Packages. Each concrete implementation should focus on discovering Packages
|
||||
// for a specific Package Type or ecosystem.
|
||||
@@ -51,6 +56,7 @@ func ImageCatalogers(cfg Config) []Cataloger {
|
||||
apkdb.NewApkdbCataloger(),
|
||||
golang.NewGoModuleBinaryCataloger(),
|
||||
dotnet.NewDotnetDepsCataloger(),
|
||||
portage.NewPortageCataloger(),
|
||||
}, cfg.Catalogers)
|
||||
}
|
||||
|
||||
@@ -73,6 +79,9 @@ func DirectoryCatalogers(cfg Config) []Cataloger {
|
||||
rust.NewCargoLockCataloger(),
|
||||
dart.NewPubspecLockCataloger(),
|
||||
dotnet.NewDotnetDepsCataloger(),
|
||||
swift.NewCocoapodsCataloger(),
|
||||
cpp.NewConanfileCataloger(),
|
||||
portage.NewPortageCataloger(),
|
||||
}, cfg.Catalogers)
|
||||
}
|
||||
|
||||
@@ -96,14 +105,33 @@ func AllCatalogers(cfg Config) []Cataloger {
|
||||
rust.NewCargoLockCataloger(),
|
||||
dart.NewPubspecLockCataloger(),
|
||||
dotnet.NewDotnetDepsCataloger(),
|
||||
php.NewPHPComposerInstalledCataloger(),
|
||||
php.NewPHPComposerLockCataloger(),
|
||||
swift.NewCocoapodsCataloger(),
|
||||
cpp.NewConanfileCataloger(),
|
||||
portage.NewPortageCataloger(),
|
||||
}, cfg.Catalogers)
|
||||
}
|
||||
|
||||
func RequestedAllCatalogers(cfg Config) bool {
|
||||
for _, enableCatalogerPattern := range cfg.Catalogers {
|
||||
if enableCatalogerPattern == AllCatalogersPattern {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func filterCatalogers(catalogers []Cataloger, enabledCatalogerPatterns []string) []Cataloger {
|
||||
// if cataloger is not set, all applicable catalogers are enabled by default
|
||||
if len(enabledCatalogerPatterns) == 0 {
|
||||
return catalogers
|
||||
}
|
||||
for _, enableCatalogerPattern := range enabledCatalogerPatterns {
|
||||
if enableCatalogerPattern == AllCatalogersPattern {
|
||||
return catalogers
|
||||
}
|
||||
}
|
||||
var keepCatalogers []Cataloger
|
||||
for _, cataloger := range catalogers {
|
||||
if contains(enabledCatalogerPatterns, cataloger.Name()) {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package cpp
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||
)
|
||||
|
||||
// NewConanfileCataloger returns a new C++ Conanfile cataloger object.
|
||||
func NewConanfileCataloger() *common.GenericCataloger {
|
||||
globParsers := map[string]common.ParserFn{
|
||||
"**/conanfile.txt": parseConanfile,
|
||||
}
|
||||
|
||||
return common.NewGenericCataloger(nil, globParsers, "conan-cataloger")
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package cpp
|
||||
|
||||
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 = parseConanfile
|
||||
|
||||
type Conanfile struct {
|
||||
Requires []string `toml:"requires"`
|
||||
}
|
||||
|
||||
// parseConanfile is a parser function for conanfile.txt contents, returning all packages discovered.
|
||||
func parseConanfile(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||
r := bufio.NewReader(reader)
|
||||
inRequirements := false
|
||||
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 conanfile.txt file: %w", err)
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(line, "[requires]"):
|
||||
inRequirements = true
|
||||
case strings.ContainsAny(line, "[]#"):
|
||||
inRequirements = false
|
||||
}
|
||||
|
||||
splits := strings.Split(strings.TrimSpace(line), "/")
|
||||
if len(splits) < 2 || !inRequirements {
|
||||
continue
|
||||
}
|
||||
pkgName, pkgVersion := splits[0], splits[1]
|
||||
pkgs = append(pkgs, &pkg.Package{
|
||||
Name: pkgName,
|
||||
Version: pkgVersion,
|
||||
Language: pkg.CPP,
|
||||
Type: pkg.ConanPkg,
|
||||
MetadataType: pkg.ConanaMetadataType,
|
||||
Metadata: pkg.ConanMetadata{
|
||||
Name: pkgName,
|
||||
Version: pkgVersion,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package cpp
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func TestParseConanfile(t *testing.T) {
|
||||
expected := []*pkg.Package{
|
||||
{
|
||||
Name: "catch2",
|
||||
Version: "2.13.8",
|
||||
Language: pkg.CPP,
|
||||
Type: pkg.ConanPkg,
|
||||
MetadataType: pkg.ConanaMetadataType,
|
||||
Metadata: pkg.ConanMetadata{
|
||||
Name: "catch2",
|
||||
Version: "2.13.8",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "docopt.cpp",
|
||||
Version: "0.6.3",
|
||||
Language: pkg.CPP,
|
||||
Type: pkg.ConanPkg,
|
||||
MetadataType: pkg.ConanaMetadataType,
|
||||
Metadata: pkg.ConanMetadata{
|
||||
Name: "docopt.cpp",
|
||||
Version: "0.6.3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "fmt",
|
||||
Version: "8.1.1",
|
||||
Language: pkg.CPP,
|
||||
Type: pkg.ConanPkg,
|
||||
MetadataType: pkg.ConanaMetadataType,
|
||||
Metadata: pkg.ConanMetadata{
|
||||
Name: "fmt",
|
||||
Version: "8.1.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "spdlog",
|
||||
Version: "1.9.2",
|
||||
Language: pkg.CPP,
|
||||
Type: pkg.ConanPkg,
|
||||
MetadataType: pkg.ConanaMetadataType,
|
||||
Metadata: pkg.ConanMetadata{
|
||||
Name: "spdlog",
|
||||
Version: "1.9.2",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "sdl",
|
||||
Version: "2.0.20",
|
||||
Language: pkg.CPP,
|
||||
Type: pkg.ConanPkg,
|
||||
MetadataType: pkg.ConanaMetadataType,
|
||||
Metadata: pkg.ConanMetadata{
|
||||
Name: "sdl",
|
||||
Version: "2.0.20",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "fltk",
|
||||
Version: "1.3.8",
|
||||
Language: pkg.CPP,
|
||||
Type: pkg.ConanPkg,
|
||||
MetadataType: pkg.ConanaMetadataType,
|
||||
Metadata: pkg.ConanMetadata{
|
||||
Name: "fltk",
|
||||
Version: "1.3.8",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fixture, err := os.Open("test-fixtures/conanfile.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
}
|
||||
|
||||
// TODO: no relationships are under test yet
|
||||
actual, _, err := parseConanfile(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,12 @@
|
||||
# Docs at https://docs.conan.io/en/latest/reference/conanfile_txt.html
|
||||
|
||||
[requires]
|
||||
catch2/2.13.8
|
||||
docopt.cpp/0.6.3
|
||||
fmt/8.1.1
|
||||
spdlog/1.9.2
|
||||
sdl/2.0.20
|
||||
fltk/1.3.8
|
||||
|
||||
[generators]
|
||||
cmake_find_package_multi
|
||||
@@ -10,11 +10,13 @@ import (
|
||||
"io"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/golang/internal/xcoff"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
"golang.org/x/mod/module"
|
||||
)
|
||||
|
||||
const GOARCH = "GOARCH"
|
||||
@@ -24,14 +26,30 @@ var (
|
||||
// appear to be in a known format, or it breaks the rules of that format,
|
||||
// or when there are I/O errors reading the file.
|
||||
errUnrecognizedFormat = errors.New("unrecognized file format")
|
||||
// devel is used to recognize the current default version when a golang main distribution is built
|
||||
// https://github.com/golang/go/issues/29228 this issue has more details on the progress of being able to
|
||||
// inject the correct version into the main module of the build process
|
||||
)
|
||||
|
||||
const devel = "(devel)"
|
||||
|
||||
func makeGoMainPackage(mod *debug.BuildInfo, arch string, location source.Location) pkg.Package {
|
||||
gbs := getBuildSettings(mod.Settings)
|
||||
main := newGoBinaryPackage(&mod.Main, mod.Main.Path, mod.GoVersion, arch, location, gbs)
|
||||
|
||||
if v, ok := gbs["vcs.revision"]; ok {
|
||||
main.Version = v
|
||||
if main.Version == devel {
|
||||
if version, ok := gbs["vcs.revision"]; ok {
|
||||
if timestamp, ok := gbs["vcs.time"]; ok {
|
||||
//NOTE: err is ignored, because if parsing fails
|
||||
// we still use the empty Time{} struct to generate an empty date, like 00010101000000
|
||||
// for consistency with the pseudo-version format: https://go.dev/ref/mod#pseudo-versions
|
||||
ts, _ := time.Parse(time.RFC3339, timestamp)
|
||||
if len(version) >= 12 {
|
||||
version = version[:12]
|
||||
}
|
||||
version = module.PseudoVersion("", "", ts, version)
|
||||
}
|
||||
main.Version = version
|
||||
}
|
||||
}
|
||||
|
||||
return main
|
||||
|
||||
@@ -63,6 +63,11 @@ func newPackageFromPom(dep gopom.Dependency) *pkg.Package {
|
||||
Type: pkg.JavaPkg, // TODO: should we differentiate between packages from jar/war/zip versus packages from a pom.xml that were not installed yet?
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
FoundBy: javaPomCataloger,
|
||||
Metadata: pkg.JavaMetadata{
|
||||
PomProperties: &pkg.PomProperties{
|
||||
GroupID: dep.GroupID,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p.Metadata = pkg.JavaMetadata{PURL: packageURL(*p)}
|
||||
|
||||
@@ -26,7 +26,7 @@ func Test_parserPomXML(t *testing.T) {
|
||||
Type: pkg.JavaPkg,
|
||||
MetadataType: pkg.JavaMetadataType,
|
||||
Metadata: pkg.JavaMetadata{
|
||||
PURL: "pkg:maven/joda-time/joda-time@2.9.2",
|
||||
PURL: "pkg:maven/com.joda/joda-time@2.9.2",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.anchore</groupId>
|
||||
@@ -16,7 +15,7 @@
|
||||
<dependencies>
|
||||
<!-- tag::joda[] -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<groupId>com.joda</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>2.9.2</version>
|
||||
</dependency>
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
Package portage provides a concrete Cataloger implementation for Gentoo Portage.
|
||||
*/
|
||||
package portage
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
var (
|
||||
cpvRe = regexp.MustCompile(`/([^/]*/[\w+][\w+-]*)-((\d+)((\.\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\d*)*)(-r\d+)?)/CONTENTS$`)
|
||||
)
|
||||
|
||||
type Cataloger struct{}
|
||||
|
||||
// NewPortageCataloger returns a new Portage package cataloger object.
|
||||
func NewPortageCataloger() *Cataloger {
|
||||
return &Cataloger{}
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes a cataloger
|
||||
func (c *Cataloger) Name() string {
|
||||
return "portage-cataloger"
|
||||
}
|
||||
|
||||
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing portage support files.
|
||||
func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
dbFileMatches, err := resolver.FilesByGlob(pkg.PortageDBGlob)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to find portage files by glob: %w", err)
|
||||
}
|
||||
var allPackages []pkg.Package
|
||||
for _, dbLocation := range dbFileMatches {
|
||||
cpvMatch := cpvRe.FindStringSubmatch(dbLocation.RealPath)
|
||||
if cpvMatch == nil {
|
||||
return nil, nil, fmt.Errorf("failed to match package and version in %s", dbLocation.RealPath)
|
||||
}
|
||||
entry := pkg.PortageMetadata{
|
||||
// ensure the default value for a collection is never nil since this may be shown as JSON
|
||||
Files: make([]pkg.PortageFileRecord, 0),
|
||||
Package: cpvMatch[1],
|
||||
Version: cpvMatch[2],
|
||||
}
|
||||
|
||||
err = addFiles(resolver, dbLocation, &entry)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
addSize(resolver, dbLocation, &entry)
|
||||
|
||||
p := pkg.Package{
|
||||
Name: entry.Package,
|
||||
Version: entry.Version,
|
||||
Type: pkg.PortagePkg,
|
||||
MetadataType: pkg.PortageMetadataType,
|
||||
Metadata: entry,
|
||||
}
|
||||
addLicenses(resolver, dbLocation, &p)
|
||||
p.FoundBy = c.Name()
|
||||
p.Locations.Add(dbLocation)
|
||||
p.SetID()
|
||||
allPackages = append(allPackages, p)
|
||||
}
|
||||
return allPackages, nil, nil
|
||||
}
|
||||
|
||||
func addFiles(resolver source.FileResolver, dbLocation source.Location, entry *pkg.PortageMetadata) error {
|
||||
contentsReader, err := resolver.FileContentsByLocation(dbLocation)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(contentsReader)
|
||||
for scanner.Scan() {
|
||||
line := strings.Trim(scanner.Text(), "\n")
|
||||
fields := strings.Split(line, " ")
|
||||
|
||||
if fields[0] == "obj" {
|
||||
record := pkg.PortageFileRecord{
|
||||
Path: fields[1],
|
||||
}
|
||||
record.Digest = &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: fields[2],
|
||||
}
|
||||
entry.Files = append(entry.Files, record)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addLicenses(resolver source.FileResolver, dbLocation source.Location, p *pkg.Package) {
|
||||
parentPath := filepath.Dir(dbLocation.RealPath)
|
||||
|
||||
location := resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "LICENSE"))
|
||||
|
||||
if location != nil {
|
||||
licenseReader, err := resolver.FileContentsByLocation(*location)
|
||||
if err == nil {
|
||||
findings := internal.NewStringSet()
|
||||
scanner := bufio.NewScanner(licenseReader)
|
||||
scanner.Split(bufio.ScanWords)
|
||||
for scanner.Scan() {
|
||||
token := scanner.Text()
|
||||
if token != "||" && token != "(" && token != ")" {
|
||||
findings.Add(token)
|
||||
}
|
||||
}
|
||||
p.Licenses = findings.ToSlice()
|
||||
|
||||
sort.Strings(p.Licenses)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addSize(resolver source.FileResolver, dbLocation source.Location, entry *pkg.PortageMetadata) {
|
||||
parentPath := filepath.Dir(dbLocation.RealPath)
|
||||
|
||||
location := resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "SIZE"))
|
||||
|
||||
if location != nil {
|
||||
sizeReader, err := resolver.FileContentsByLocation(*location)
|
||||
if err != nil {
|
||||
log.Warnf("failed to fetch portage SIZE (package=%s): %+v", entry.Package, err)
|
||||
} else {
|
||||
scanner := bufio.NewScanner(sizeReader)
|
||||
for scanner.Scan() {
|
||||
line := strings.Trim(scanner.Text(), "\n")
|
||||
size, err := strconv.Atoi(line)
|
||||
if err == nil {
|
||||
entry.InstalledSize = size
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package portage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func TestPortageCataloger(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
expected []pkg.Package
|
||||
}{
|
||||
{
|
||||
name: "go-case",
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "app-containers/skopeo",
|
||||
Version: "1.5.1",
|
||||
FoundBy: "portage-cataloger",
|
||||
Licenses: []string{"Apache-2.0", "BSD", "BSD-2", "CC-BY-SA-4.0", "ISC", "MIT"},
|
||||
Type: pkg.PortagePkg,
|
||||
MetadataType: pkg.PortageMetadataType,
|
||||
Metadata: pkg.PortageMetadata{
|
||||
Package: "app-containers/skopeo",
|
||||
Version: "1.5.1",
|
||||
InstalledSize: 27937835,
|
||||
Files: []pkg.PortageFileRecord{
|
||||
{
|
||||
Path: "/usr/bin/skopeo",
|
||||
Digest: &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: "376c02bd3b22804df8fdfdc895e7dbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/etc/containers/policy.json",
|
||||
Digest: &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: "c01eb6950f03419e09d4fc88cb42ff6f",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/etc/containers/registries.d/default.yaml",
|
||||
Digest: &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: "e6e66cd3c24623e0667f26542e0e08f6",
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "/var/lib/atomic/sigstore/.keep_app-containers_skopeo-0",
|
||||
Digest: &file.Digest{
|
||||
Algorithm: "md5",
|
||||
Value: "d41d8cd98f00b204e9800998ecf8427e",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
img := imagetest.GetFixtureImage(t, "docker-archive", "image-portage")
|
||||
|
||||
s, err := source.NewFromImage(img, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := NewPortageCataloger()
|
||||
|
||||
resolver, err := s.FileResolver(source.SquashedScope)
|
||||
if err != nil {
|
||||
t.Errorf("could not get resolver error: %+v", err)
|
||||
}
|
||||
|
||||
actual, _, err := c.Catalog(resolver)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to catalog: %+v", err)
|
||||
}
|
||||
|
||||
if len(actual) != len(test.expected) {
|
||||
for _, a := range actual {
|
||||
t.Logf(" %+v", a)
|
||||
}
|
||||
t.Fatalf("unexpected package count: %d!=%d", len(actual), len(test.expected))
|
||||
}
|
||||
|
||||
// test remaining fields...
|
||||
for _, d := range deep.Equal(actual, test.expected) {
|
||||
t.Errorf("diff: %+v", d)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
FROM scratch
|
||||
COPY . .
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
dir /usr
|
||||
dir /usr/bin
|
||||
obj /usr/bin/skopeo 376c02bd3b22804df8fdfdc895e7dbfb 1649284374
|
||||
dir /etc
|
||||
dir /etc/containers
|
||||
obj /etc/containers/policy.json c01eb6950f03419e09d4fc88cb42ff6f 1649284375
|
||||
dir /etc/containers/registries.d
|
||||
obj /etc/containers/registries.d/default.yaml e6e66cd3c24623e0667f26542e0e08f6 1649284375
|
||||
dir /var
|
||||
dir /var/lib
|
||||
dir /var/lib/atomic
|
||||
dir /var/lib/atomic/sigstore
|
||||
obj /var/lib/atomic/sigstore/.keep_app-containers_skopeo-0 d41d8cd98f00b204e9800998ecf8427e 1649284375
|
||||
+1
@@ -0,0 +1 @@
|
||||
Apache-2.0 BSD BSD-2 CC-BY-SA-4.0 ISC MIT
|
||||
+1
@@ -0,0 +1 @@
|
||||
27937835
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
Package swift provides a concrete Cataloger implementation for Podfile.lock files.
|
||||
*/
|
||||
package swift
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
||||
)
|
||||
|
||||
// NewCocoapodsCataloger returns a new Swift Cocoapods lock file cataloger object.
|
||||
func NewCocoapodsCataloger() *common.GenericCataloger {
|
||||
globParsers := map[string]common.ParserFn{
|
||||
"**/Podfile.lock": parsePodfileLock,
|
||||
}
|
||||
|
||||
return common.NewGenericCataloger(nil, globParsers, "cocoapods-cataloger")
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package swift
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"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 = parsePodfileLock
|
||||
|
||||
// parsePodfileLock is a parser function for Podfile.lock contents, returning all cocoapods pods discovered.
|
||||
func parsePodfileLock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||
bytes, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to read file: %w", err)
|
||||
}
|
||||
var podfile map[string]interface{}
|
||||
if err = yaml.Unmarshal(bytes, &podfile); err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to parse yaml: %w", err)
|
||||
}
|
||||
|
||||
c, exists := podfile["SPEC CHECKSUMS"]
|
||||
if !exists {
|
||||
return nil, nil, fmt.Errorf("malformed podfile.lock: missing checksums")
|
||||
}
|
||||
checksums := c.(map[string]interface{})
|
||||
p, exists := podfile["PODS"]
|
||||
if !exists {
|
||||
return nil, nil, fmt.Errorf("malformed podfile.lock: missing checksums")
|
||||
}
|
||||
pods := p.([]interface{})
|
||||
|
||||
pkgs := []*pkg.Package{}
|
||||
for _, podInterface := range pods {
|
||||
var podBlob string
|
||||
switch v := podInterface.(type) {
|
||||
case map[string]interface{}:
|
||||
for k := range v {
|
||||
podBlob = k
|
||||
}
|
||||
case string:
|
||||
podBlob = v
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("malformed podfile.lock")
|
||||
}
|
||||
splits := strings.Split(podBlob, " ")
|
||||
podName := splits[0]
|
||||
podVersion := strings.TrimSuffix(strings.TrimPrefix(splits[1], "("), ")")
|
||||
podRootPkg := strings.Split(podName, "/")[0]
|
||||
pkgHash, exists := checksums[podRootPkg]
|
||||
if !exists {
|
||||
return nil, nil, fmt.Errorf("malformed podfile.lock: incomplete checksums")
|
||||
}
|
||||
pkgs = append(pkgs, &pkg.Package{
|
||||
Name: podName,
|
||||
Version: podVersion,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
Language: pkg.Swift,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: podName,
|
||||
Version: podVersion,
|
||||
PkgHash: pkgHash.(string),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
package swift
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func TestParsePodfileLock(t *testing.T) {
|
||||
expected := []*pkg.Package{
|
||||
{
|
||||
Name: "GlossButtonNode",
|
||||
Version: "3.1.2",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "GlossButtonNode",
|
||||
Version: "3.1.2",
|
||||
PkgHash: "4ea1197a744f2fb5fb875fe31caf17ded4762e8f",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINCache",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINCache",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "7a8fc1a691173d21dbddbf86cd515de6efa55086",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINCache/Arc-exception-safe",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINCache/Arc-exception-safe",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "7a8fc1a691173d21dbddbf86cd515de6efa55086",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINCache/Core",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINCache/Core",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "7a8fc1a691173d21dbddbf86cd515de6efa55086",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINOperation",
|
||||
Version: "1.2.1",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINOperation",
|
||||
Version: "1.2.1",
|
||||
PkgHash: "00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINRemoteImage/Core",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINRemoteImage/Core",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "f1295b29f8c5e640e25335a1b2bd9d805171bd01",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINRemoteImage/iOS",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINRemoteImage/iOS",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "f1295b29f8c5e640e25335a1b2bd9d805171bd01",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "PINRemoteImage/PINCache",
|
||||
Version: "3.0.3",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "PINRemoteImage/PINCache",
|
||||
Version: "3.0.3",
|
||||
PkgHash: "f1295b29f8c5e640e25335a1b2bd9d805171bd01",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Reveal-SDK",
|
||||
Version: "33",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Reveal-SDK",
|
||||
Version: "33",
|
||||
PkgHash: "effba1c940b8337195563c425a6b5862ec875caa",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "SwiftGen",
|
||||
Version: "6.5.1",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "SwiftGen",
|
||||
Version: "6.5.1",
|
||||
PkgHash: "a6d22010845f08fe18fbdf3a07a8e380fd22e0ea",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/AssetsLibrary",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/AssetsLibrary",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/Core",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/Core",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/MapKit",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/MapKit",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/Photos",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/Photos",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/PINRemoteImage",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/PINRemoteImage",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Texture/Video",
|
||||
Version: "3.1.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "Texture/Video",
|
||||
Version: "3.1.0",
|
||||
PkgHash: "2e8ab2519452515f7f5a520f5a8f7e0a413abfa3",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport/Components",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport/Components",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport/Experiments",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport/Experiments",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport/Extensions",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport/Extensions",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TextureSwiftSupport/LayoutSpecBuilders",
|
||||
Version: "3.13.0",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TextureSwiftSupport/LayoutSpecBuilders",
|
||||
Version: "3.13.0",
|
||||
PkgHash: "c515c7927fab92d0d9485f49b885b8c5de34fbfb",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TinyConstraints",
|
||||
Version: "4.0.2",
|
||||
Language: pkg.Swift,
|
||||
Type: pkg.CocoapodsPkg,
|
||||
MetadataType: pkg.CocoapodsMetadataType,
|
||||
Metadata: pkg.CocoapodsMetadata{
|
||||
Name: "TinyConstraints",
|
||||
Version: "4.0.2",
|
||||
PkgHash: "7b7ccc0c485bb3bb47082138ff28bc33cd49897f",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
fixture, err := os.Open("test-fixtures/Podfile.lock")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
}
|
||||
|
||||
// TODO: no relationships are under test yet
|
||||
actual, _, err := parsePodfileLock(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,92 @@
|
||||
PODS:
|
||||
- GlossButtonNode (3.1.2):
|
||||
- Texture/Core (~> 3)
|
||||
- TextureSwiftSupport (>= 3.10.0)
|
||||
- PINCache (3.0.3):
|
||||
- PINCache/Arc-exception-safe (= 3.0.3)
|
||||
- PINCache/Core (= 3.0.3)
|
||||
- PINCache/Arc-exception-safe (3.0.3):
|
||||
- PINCache/Core
|
||||
- PINCache/Core (3.0.3):
|
||||
- PINOperation (~> 1.2.1)
|
||||
- PINOperation (1.2.1)
|
||||
- PINRemoteImage/Core (3.0.3):
|
||||
- PINOperation
|
||||
- PINRemoteImage/iOS (3.0.3):
|
||||
- PINRemoteImage/Core
|
||||
- PINRemoteImage/PINCache (3.0.3):
|
||||
- PINCache (~> 3.0.3)
|
||||
- PINRemoteImage/Core
|
||||
- Reveal-SDK (33)
|
||||
- SwiftGen (6.5.1)
|
||||
- Texture (3.1.0):
|
||||
- Texture/AssetsLibrary (= 3.1.0)
|
||||
- Texture/Core (= 3.1.0)
|
||||
- Texture/MapKit (= 3.1.0)
|
||||
- Texture/Photos (= 3.1.0)
|
||||
- Texture/PINRemoteImage (= 3.1.0)
|
||||
- Texture/Video (= 3.1.0)
|
||||
- Texture/AssetsLibrary (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/Core (3.1.0)
|
||||
- Texture/MapKit (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/Photos (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/PINRemoteImage (3.1.0):
|
||||
- PINRemoteImage/iOS (~> 3.0.0)
|
||||
- PINRemoteImage/PINCache
|
||||
- Texture/Core
|
||||
- Texture/Video (3.1.0):
|
||||
- Texture/Core
|
||||
- TextureSwiftSupport (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/Components (= 3.13.0)
|
||||
- TextureSwiftSupport/Experiments (= 3.13.0)
|
||||
- TextureSwiftSupport/Extensions (= 3.13.0)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders (= 3.13.0)
|
||||
- TextureSwiftSupport/Components (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders
|
||||
- TextureSwiftSupport/Experiments (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/Extensions (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TinyConstraints (4.0.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- GlossButtonNode
|
||||
- Reveal-SDK
|
||||
- SwiftGen
|
||||
- Texture
|
||||
- TextureSwiftSupport
|
||||
- TinyConstraints
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- GlossButtonNode
|
||||
- PINCache
|
||||
- PINOperation
|
||||
- PINRemoteImage
|
||||
- Reveal-SDK
|
||||
- SwiftGen
|
||||
- Texture
|
||||
- TextureSwiftSupport
|
||||
- TinyConstraints
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
GlossButtonNode: 4ea1197a744f2fb5fb875fe31caf17ded4762e8f
|
||||
PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086
|
||||
PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20
|
||||
PINRemoteImage: f1295b29f8c5e640e25335a1b2bd9d805171bd01
|
||||
Reveal-SDK: effba1c940b8337195563c425a6b5862ec875caa
|
||||
SwiftGen: a6d22010845f08fe18fbdf3a07a8e380fd22e0ea
|
||||
Texture: 2e8ab2519452515f7f5a520f5a8f7e0a413abfa3
|
||||
TextureSwiftSupport: c515c7927fab92d0d9485f49b885b8c5de34fbfb
|
||||
TinyConstraints: 7b7ccc0c485bb3bb47082138ff28bc33cd49897f
|
||||
|
||||
PODFILE CHECKSUM: 07aa55f54421f6e6d3a920c11716a89fc9243d1b
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
@@ -0,0 +1,27 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
)
|
||||
|
||||
var _ urlIdentifier = (*CocoapodsMetadata)(nil)
|
||||
|
||||
type CocoapodsMetadata struct {
|
||||
Name string `mapstructure:"name" json:"name"`
|
||||
Version string `mapstructure:"version" json:"version"`
|
||||
PkgHash string `mapstructure:"pkgHash" json:"pkgHash"`
|
||||
}
|
||||
|
||||
func (m CocoapodsMetadata) PackageURL(_ *linux.Release) string {
|
||||
var qualifiers packageurl.Qualifiers
|
||||
|
||||
return packageurl.NewPackageURL(
|
||||
packageurl.TypeCocoapods,
|
||||
"",
|
||||
m.Name,
|
||||
m.Version,
|
||||
qualifiers,
|
||||
"",
|
||||
).ToString()
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
)
|
||||
|
||||
type ConanMetadata struct {
|
||||
Name string `mapstructure:"name" json:"name"`
|
||||
Version string `mapstructure:"version" json:"version"`
|
||||
}
|
||||
|
||||
func (m ConanMetadata) PackageURL(_ *linux.Release) string {
|
||||
var qualifiers packageurl.Qualifiers
|
||||
|
||||
return packageurl.NewPackageURL(
|
||||
packageurl.TypeConan,
|
||||
"",
|
||||
m.Name,
|
||||
m.Version,
|
||||
qualifiers,
|
||||
"",
|
||||
).ToString()
|
||||
}
|
||||
@@ -21,6 +21,8 @@ const (
|
||||
Rust Language = "rust"
|
||||
Dart Language = "dart"
|
||||
Dotnet Language = "dotnet"
|
||||
Swift Language = "swift"
|
||||
CPP Language = "c++"
|
||||
)
|
||||
|
||||
// AllLanguages is a set of all programming languages detected by syft.
|
||||
@@ -34,6 +36,8 @@ var AllLanguages = []Language{
|
||||
Rust,
|
||||
Dart,
|
||||
Dotnet,
|
||||
Swift,
|
||||
CPP,
|
||||
}
|
||||
|
||||
// String returns the string representation of the language.
|
||||
@@ -58,7 +62,7 @@ func LanguageByName(name string) Language {
|
||||
return PHP
|
||||
case packageurl.TypeGolang, string(GoModulePkg), string(Go):
|
||||
return Go
|
||||
case packageurl.TypeNPM, string(JavaScript):
|
||||
case packageurl.TypeNPM, string(JavaScript), "nodejs", "node.js":
|
||||
return JavaScript
|
||||
case packageurl.TypePyPi, string(Python):
|
||||
return Python
|
||||
@@ -70,6 +74,10 @@ func LanguageByName(name string) Language {
|
||||
return Dart
|
||||
case packageurl.TypeDotnet:
|
||||
return Dotnet
|
||||
case packageurl.TypeCocoapods, packageurl.TypeSwift, string(CocoapodsPkg):
|
||||
return Swift
|
||||
case packageurl.TypeConan, string(CPP):
|
||||
return CPP
|
||||
default:
|
||||
return UnknownLanguage
|
||||
}
|
||||
|
||||
@@ -50,6 +50,14 @@ func TestLanguageFromPURL(t *testing.T) {
|
||||
purl: "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?type=zip&classifier=dist",
|
||||
want: Java,
|
||||
},
|
||||
{
|
||||
purl: "pkg:cocoapods/GlossButtonNode@3.1.2",
|
||||
want: Swift,
|
||||
},
|
||||
{
|
||||
purl: "pkg:conan/catch2@2.13.8",
|
||||
want: CPP,
|
||||
},
|
||||
}
|
||||
|
||||
var languages []string
|
||||
@@ -127,6 +135,14 @@ func TestLanguageByName(t *testing.T) {
|
||||
name: "javascript",
|
||||
language: JavaScript,
|
||||
},
|
||||
{
|
||||
name: "node.js",
|
||||
language: JavaScript,
|
||||
},
|
||||
{
|
||||
name: "nodejs",
|
||||
language: JavaScript,
|
||||
},
|
||||
{
|
||||
name: "pypi",
|
||||
language: Python,
|
||||
@@ -171,10 +187,30 @@ func TestLanguageByName(t *testing.T) {
|
||||
name: "dotnet",
|
||||
language: Dotnet,
|
||||
},
|
||||
{
|
||||
name: "swift",
|
||||
language: Swift,
|
||||
},
|
||||
{
|
||||
name: "pod",
|
||||
language: Swift,
|
||||
},
|
||||
{
|
||||
name: "cocoapods",
|
||||
language: Swift,
|
||||
},
|
||||
{
|
||||
name: "unknown",
|
||||
language: UnknownLanguage,
|
||||
},
|
||||
{
|
||||
name: "conan",
|
||||
language: CPP,
|
||||
},
|
||||
{
|
||||
name: "c++",
|
||||
language: CPP,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -25,6 +25,9 @@ const (
|
||||
KbPackageMetadataType MetadataType = "KbPackageMetadata"
|
||||
GolangBinMetadataType MetadataType = "GolangBinMetadata"
|
||||
PhpComposerJSONMetadataType MetadataType = "PhpComposerJsonMetadata"
|
||||
CocoapodsMetadataType MetadataType = "CocoapodsMetadataType"
|
||||
ConanaMetadataType MetadataType = "ConanaMetadataType"
|
||||
PortageMetadataType MetadataType = "PortageMetadata"
|
||||
)
|
||||
|
||||
var AllMetadataTypes = []MetadataType{
|
||||
@@ -42,6 +45,9 @@ var AllMetadataTypes = []MetadataType{
|
||||
KbPackageMetadataType,
|
||||
GolangBinMetadataType,
|
||||
PhpComposerJSONMetadataType,
|
||||
CocoapodsMetadataType,
|
||||
ConanaMetadataType,
|
||||
PortageMetadataType,
|
||||
}
|
||||
|
||||
var MetadataTypeByName = map[MetadataType]reflect.Type{
|
||||
@@ -59,4 +65,7 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{
|
||||
KbPackageMetadataType: reflect.TypeOf(KbPackageMetadata{}),
|
||||
GolangBinMetadataType: reflect.TypeOf(GolangBinMetadata{}),
|
||||
PhpComposerJSONMetadataType: reflect.TypeOf(PhpComposerJSONMetadata{}),
|
||||
CocoapodsMetadataType: reflect.TypeOf(CocoapodsMetadata{}),
|
||||
ConanaMetadataType: reflect.TypeOf(ConanMetadata{}),
|
||||
PortageMetadataType: reflect.TypeOf(PortageMetadata{}),
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
|
||||
const PortageDBGlob = "**/var/db/pkg/*/*/CONTENTS"
|
||||
|
||||
// PortageMetadata represents all captured data for a Package package DB entry.
|
||||
type PortageMetadata struct {
|
||||
Package string `mapstructure:"Package" json:"package"`
|
||||
Version string `mapstructure:"Version" json:"version"`
|
||||
InstalledSize int `mapstructure:"InstalledSize" json:"installedSize" cyclonedx:"installedSize"`
|
||||
Files []PortageFileRecord `json:"files"`
|
||||
}
|
||||
|
||||
// PortageFileRecord represents a single file attributed to a portage package.
|
||||
type PortageFileRecord struct {
|
||||
Path string `json:"path"`
|
||||
Digest *file.Digest `json:"digest,omitempty"`
|
||||
}
|
||||
@@ -7,12 +7,17 @@ import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
)
|
||||
|
||||
// AltRpmDBGlob allows db matches against new locations introduced in fedora:{36,37}
|
||||
// See https://github.com/anchore/syft/issues/1077 for larger context
|
||||
const AltRpmDBGlob = "**/rpm/{Packages,Packages.db,rpmdb.sqlite}"
|
||||
|
||||
var globsForbiddenFromBeingOwned = []string{
|
||||
// any OS DBs should automatically be ignored to prevent cyclic issues (e.g. the "rpm" RPM owns the path to the
|
||||
// RPM DB, so if not ignored that package would own all other packages on the system).
|
||||
ApkDBGlob,
|
||||
DpkgDBGlob,
|
||||
RpmDBGlob,
|
||||
AltRpmDBGlob,
|
||||
// DEB packages share common copyright info between, this does not mean that sharing these paths implies ownership.
|
||||
"/usr/share/doc/**/copyright",
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ const (
|
||||
KbPkg Type = "msrc-kb"
|
||||
DartPubPkg Type = "dart-pub"
|
||||
DotnetPkg Type = "dotnet"
|
||||
CocoapodsPkg Type = "pod"
|
||||
ConanPkg Type = "conan"
|
||||
PortagePkg Type = "portage"
|
||||
)
|
||||
|
||||
// AllPkgs represents all supported package types
|
||||
@@ -42,6 +45,9 @@ var AllPkgs = []Type{
|
||||
KbPkg,
|
||||
DartPubPkg,
|
||||
DotnetPkg,
|
||||
CocoapodsPkg,
|
||||
ConanPkg,
|
||||
PortagePkg,
|
||||
}
|
||||
|
||||
// PackageURLType returns the PURL package type for the current package.
|
||||
@@ -73,6 +79,12 @@ func (t Type) PackageURLType() string {
|
||||
return packageurl.TypePub
|
||||
case DotnetPkg:
|
||||
return packageurl.TypeDotnet
|
||||
case CocoapodsPkg:
|
||||
return packageurl.TypeCocoapods
|
||||
case ConanPkg:
|
||||
return packageurl.TypeConan
|
||||
case PortagePkg:
|
||||
return "portage"
|
||||
default:
|
||||
// TODO: should this be a "generic" purl type instead?
|
||||
return ""
|
||||
@@ -116,6 +128,12 @@ func TypeByName(name string) Type {
|
||||
return DartPubPkg
|
||||
case packageurl.TypeDotnet:
|
||||
return DotnetPkg
|
||||
case packageurl.TypeCocoapods:
|
||||
return CocoapodsPkg
|
||||
case packageurl.TypeConan:
|
||||
return ConanPkg
|
||||
case "portage":
|
||||
return PortagePkg
|
||||
default:
|
||||
return UnknownPkg
|
||||
}
|
||||
|
||||
@@ -68,6 +68,14 @@ func TestTypeFromPURL(t *testing.T) {
|
||||
purl: "pkg:alpm/arch/linux@5.10.0?arch=x86_64&distro=arch",
|
||||
expected: AlpmPkg,
|
||||
},
|
||||
{
|
||||
purl: "pkg:cocoapods/GlossButtonNode@3.1.2",
|
||||
expected: CocoapodsPkg,
|
||||
},
|
||||
{
|
||||
purl: "pkg:conan/catch2@2.13.8",
|
||||
expected: ConanPkg,
|
||||
},
|
||||
}
|
||||
|
||||
var pkgTypes []string
|
||||
@@ -79,6 +87,7 @@ func TestTypeFromPURL(t *testing.T) {
|
||||
// testing microsoft packages and jenkins-plugins is not valid for purl at this time
|
||||
expectedTypes.Remove(string(KbPkg))
|
||||
expectedTypes.Remove(string(JenkinsPluginPkg))
|
||||
expectedTypes.Remove(string(PortagePkg))
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(string(test.expected), func(t *testing.T) {
|
||||
|
||||
+4
-2
@@ -47,8 +47,10 @@ func URL(p Package, release *linux.Release) string {
|
||||
case p.Type == GoModulePkg:
|
||||
re := regexp.MustCompile(`(/)[^/]*$`)
|
||||
fields := re.Split(p.Name, -1)
|
||||
namespace = fields[0]
|
||||
name = strings.TrimPrefix(p.Name, namespace+"/")
|
||||
if len(fields) > 1 {
|
||||
namespace = fields[0]
|
||||
name = strings.TrimPrefix(p.Name, namespace+"/")
|
||||
}
|
||||
case p.Type == NpmPkg:
|
||||
fields := strings.SplitN(p.Name, "/", 2)
|
||||
if len(fields) > 1 {
|
||||
|
||||
+50
-1
@@ -25,6 +25,15 @@ func TestPackageURL(t *testing.T) {
|
||||
},
|
||||
expected: "pkg:golang/github.com/anchore/syft@v0.1.0",
|
||||
},
|
||||
{
|
||||
name: "golang short name",
|
||||
pkg: Package{
|
||||
Name: "go.opencensus.io",
|
||||
Version: "v0.23.0",
|
||||
Type: GoModulePkg,
|
||||
},
|
||||
expected: "pkg:golang/go.opencensus.io@v0.23.0",
|
||||
},
|
||||
{
|
||||
name: "pub",
|
||||
pkg: Package{
|
||||
@@ -208,6 +217,35 @@ func TestPackageURL(t *testing.T) {
|
||||
|
||||
expected: "pkg:alpm/arch/linux@5.10.0?distro=arch-rolling",
|
||||
},
|
||||
{
|
||||
name: "cocoapods",
|
||||
pkg: Package{
|
||||
Name: "GlossButtonNode",
|
||||
Version: "3.1.2",
|
||||
Language: Swift,
|
||||
Type: CocoapodsPkg,
|
||||
Metadata: CocoapodsMetadata{
|
||||
Name: "GlossButtonNode",
|
||||
Version: "3.1.2",
|
||||
},
|
||||
},
|
||||
expected: "pkg:cocoapods/GlossButtonNode@3.1.2",
|
||||
},
|
||||
{
|
||||
name: "conan",
|
||||
pkg: Package{
|
||||
Name: "catch2",
|
||||
Version: "2.13.8",
|
||||
Type: ConanPkg,
|
||||
Language: CPP,
|
||||
MetadataType: ConanaMetadataType,
|
||||
Metadata: ConanMetadata{
|
||||
Name: "catch2",
|
||||
Version: "2.13.8",
|
||||
},
|
||||
},
|
||||
expected: "pkg:conan/catch2@2.13.8",
|
||||
},
|
||||
}
|
||||
|
||||
var pkgTypes []string
|
||||
@@ -218,10 +256,11 @@ func TestPackageURL(t *testing.T) {
|
||||
|
||||
// testing microsoft packages is not valid for purl at this time
|
||||
expectedTypes.Remove(string(KbPkg))
|
||||
expectedTypes.Remove(string(PortagePkg))
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if test.pkg.Type != "" {
|
||||
if test.pkg.Type != "" && !contains(pkgTypes, string(test.pkg.Type)) {
|
||||
pkgTypes = append(pkgTypes, string(test.pkg.Type))
|
||||
}
|
||||
actual := URL(test.pkg, test.distro)
|
||||
@@ -234,3 +273,13 @@ func TestPackageURL(t *testing.T) {
|
||||
}
|
||||
assert.ElementsMatch(t, expectedTypes.List(), pkgTypes, "missing one or more package types to test against (maybe a package type was added?)")
|
||||
}
|
||||
|
||||
func contains(values []string, val string) bool {
|
||||
for _, v := range values {
|
||||
if val == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ func TestPackagesCmdFlags(t *testing.T) {
|
||||
name: "squashed-scope-flag",
|
||||
args: []string{"packages", "-o", "json", "-s", "squashed", coverageImage},
|
||||
assertions: []traitAssertion{
|
||||
assertPackageCount(33),
|
||||
assertPackageCount(34),
|
||||
assertSuccessfulReturnCode,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -167,6 +167,19 @@ var dirOnlyTestCases = []testCase{
|
||||
"github.com/bmatcuk/doublestar": "v1.3.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find conan packages",
|
||||
pkgType: pkg.ConanPkg,
|
||||
pkgLanguage: pkg.CPP,
|
||||
pkgInfo: map[string]string{
|
||||
"catch2": "2.13.8",
|
||||
"docopt.cpp": "0.6.3",
|
||||
"fmt": "8.1.1",
|
||||
"spdlog": "1.9.2",
|
||||
"sdl": "2.0.20",
|
||||
"fltk": "1.3.8",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find rust crates",
|
||||
pkgType: pkg.RustPkg,
|
||||
@@ -238,6 +251,36 @@ var dirOnlyTestCases = []testCase{
|
||||
"junit": "4.12",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find cocoapods packages",
|
||||
pkgType: pkg.CocoapodsPkg,
|
||||
pkgLanguage: pkg.Swift,
|
||||
pkgInfo: map[string]string{
|
||||
"GlossButtonNode": "3.1.2",
|
||||
"PINCache": "3.0.3",
|
||||
"PINCache/Arc-exception-safe": "3.0.3",
|
||||
"PINCache/Core": "3.0.3",
|
||||
"PINOperation": "1.2.1",
|
||||
"PINRemoteImage/Core": "3.0.3",
|
||||
"PINRemoteImage/iOS": "3.0.3",
|
||||
"PINRemoteImage/PINCache": "3.0.3",
|
||||
"Reveal-SDK": "33",
|
||||
"SwiftGen": "6.5.1",
|
||||
"Texture": "3.1.0",
|
||||
"Texture/AssetsLibrary": "3.1.0",
|
||||
"Texture/Core": "3.1.0",
|
||||
"Texture/MapKit": "3.1.0",
|
||||
"Texture/Photos": "3.1.0",
|
||||
"Texture/PINRemoteImage": "3.1.0",
|
||||
"Texture/Video": "3.1.0",
|
||||
"TextureSwiftSupport": "3.13.0",
|
||||
"TextureSwiftSupport/Components": "3.13.0",
|
||||
"TextureSwiftSupport/Experiments": "3.13.0",
|
||||
"TextureSwiftSupport/Extensions": "3.13.0",
|
||||
"TextureSwiftSupport/LayoutSpecBuilders": "3.13.0",
|
||||
"TinyConstraints": "4.0.2",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var commonTestCases = []testCase{
|
||||
@@ -264,6 +307,13 @@ var commonTestCases = []testCase{
|
||||
"netbase": "5.4",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find portage packages",
|
||||
pkgType: pkg.PortagePkg,
|
||||
pkgInfo: map[string]string{
|
||||
"app-containers/skopeo": "1.5.1",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "find jenkins plugins",
|
||||
|
||||
@@ -67,6 +67,8 @@ func TestPkgCoverageImage(t *testing.T) {
|
||||
definedLanguages.Remove(pkg.Rust.String())
|
||||
definedLanguages.Remove(pkg.Dart.String())
|
||||
definedLanguages.Remove(pkg.Dotnet.String())
|
||||
definedLanguages.Remove(string(pkg.Swift.String()))
|
||||
definedLanguages.Remove(pkg.CPP.String())
|
||||
|
||||
observedPkgs := internal.NewStringSet()
|
||||
definedPkgs := internal.NewStringSet()
|
||||
@@ -80,6 +82,8 @@ func TestPkgCoverageImage(t *testing.T) {
|
||||
definedPkgs.Remove(string(pkg.RustPkg))
|
||||
definedPkgs.Remove(string(pkg.DartPubPkg))
|
||||
definedPkgs.Remove(string(pkg.DotnetPkg))
|
||||
definedPkgs.Remove(string(pkg.CocoapodsPkg))
|
||||
definedPkgs.Remove(string(pkg.ConanPkg))
|
||||
|
||||
var cases []testCase
|
||||
cases = append(cases, commonTestCases...)
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
PODS:
|
||||
- GlossButtonNode (3.1.2):
|
||||
- Texture/Core (~> 3)
|
||||
- TextureSwiftSupport (>= 3.10.0)
|
||||
- PINCache (3.0.3):
|
||||
- PINCache/Arc-exception-safe (= 3.0.3)
|
||||
- PINCache/Core (= 3.0.3)
|
||||
- PINCache/Arc-exception-safe (3.0.3):
|
||||
- PINCache/Core
|
||||
- PINCache/Core (3.0.3):
|
||||
- PINOperation (~> 1.2.1)
|
||||
- PINOperation (1.2.1)
|
||||
- PINRemoteImage/Core (3.0.3):
|
||||
- PINOperation
|
||||
- PINRemoteImage/iOS (3.0.3):
|
||||
- PINRemoteImage/Core
|
||||
- PINRemoteImage/PINCache (3.0.3):
|
||||
- PINCache (~> 3.0.3)
|
||||
- PINRemoteImage/Core
|
||||
- Reveal-SDK (33)
|
||||
- SwiftGen (6.5.1)
|
||||
- Texture (3.1.0):
|
||||
- Texture/AssetsLibrary (= 3.1.0)
|
||||
- Texture/Core (= 3.1.0)
|
||||
- Texture/MapKit (= 3.1.0)
|
||||
- Texture/Photos (= 3.1.0)
|
||||
- Texture/PINRemoteImage (= 3.1.0)
|
||||
- Texture/Video (= 3.1.0)
|
||||
- Texture/AssetsLibrary (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/Core (3.1.0)
|
||||
- Texture/MapKit (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/Photos (3.1.0):
|
||||
- Texture/Core
|
||||
- Texture/PINRemoteImage (3.1.0):
|
||||
- PINRemoteImage/iOS (~> 3.0.0)
|
||||
- PINRemoteImage/PINCache
|
||||
- Texture/Core
|
||||
- Texture/Video (3.1.0):
|
||||
- Texture/Core
|
||||
- TextureSwiftSupport (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/Components (= 3.13.0)
|
||||
- TextureSwiftSupport/Experiments (= 3.13.0)
|
||||
- TextureSwiftSupport/Extensions (= 3.13.0)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders (= 3.13.0)
|
||||
- TextureSwiftSupport/Components (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders
|
||||
- TextureSwiftSupport/Experiments (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/Extensions (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TextureSwiftSupport/LayoutSpecBuilders (3.13.0):
|
||||
- Texture/Core (>= 3)
|
||||
- TinyConstraints (4.0.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- GlossButtonNode
|
||||
- Reveal-SDK
|
||||
- SwiftGen
|
||||
- Texture
|
||||
- TextureSwiftSupport
|
||||
- TinyConstraints
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- GlossButtonNode
|
||||
- PINCache
|
||||
- PINOperation
|
||||
- PINRemoteImage
|
||||
- Reveal-SDK
|
||||
- SwiftGen
|
||||
- Texture
|
||||
- TextureSwiftSupport
|
||||
- TinyConstraints
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
GlossButtonNode: 4ea1197a744f2fb5fb875fe31caf17ded4762e8f
|
||||
PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086
|
||||
PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20
|
||||
PINRemoteImage: f1295b29f8c5e640e25335a1b2bd9d805171bd01
|
||||
Reveal-SDK: effba1c940b8337195563c425a6b5862ec875caa
|
||||
SwiftGen: a6d22010845f08fe18fbdf3a07a8e380fd22e0ea
|
||||
Texture: 2e8ab2519452515f7f5a520f5a8f7e0a413abfa3
|
||||
TextureSwiftSupport: c515c7927fab92d0d9485f49b885b8c5de34fbfb
|
||||
TinyConstraints: 7b7ccc0c485bb3bb47082138ff28bc33cd49897f
|
||||
|
||||
PODFILE CHECKSUM: 07aa55f54421f6e6d3a920c11716a89fc9243d1b
|
||||
|
||||
COCOAPODS: 1.11.2
|
||||
@@ -0,0 +1,12 @@
|
||||
# Docs at https://docs.conan.io/en/latest/reference/conanfile_txt.html
|
||||
|
||||
[requires]
|
||||
catch2/2.13.8
|
||||
docopt.cpp/0.6.3
|
||||
fmt/8.1.1
|
||||
spdlog/1.9.2
|
||||
sdl/2.0.20
|
||||
fltk/1.3.8
|
||||
|
||||
[generators]
|
||||
cmake_find_package_multi
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
dir /usr
|
||||
dir /usr/bin
|
||||
obj /usr/bin/skopeo 376c02bd3b22804df8fdfdc895e7dbfb 1649284374
|
||||
dir /etc
|
||||
dir /etc/containers
|
||||
obj /etc/containers/policy.json c01eb6950f03419e09d4fc88cb42ff6f 1649284375
|
||||
dir /etc/containers/registries.d
|
||||
obj /etc/containers/registries.d/default.yaml e6e66cd3c24623e0667f26542e0e08f6 1649284375
|
||||
dir /var
|
||||
dir /var/lib
|
||||
dir /var/lib/atomic
|
||||
dir /var/lib/atomic/sigstore
|
||||
obj /var/lib/atomic/sigstore/.keep_app-containers_skopeo-0 d41d8cd98f00b204e9800998ecf8427e 1649284375
|
||||
+1
@@ -0,0 +1 @@
|
||||
Apache-2.0 BSD BSD-2 CC-BY-SA-4.0 ISC MIT
|
||||
+1
@@ -0,0 +1 @@
|
||||
27937835
|
||||
Reference in New Issue
Block a user