diff --git a/.golangci.yaml b/.golangci.yaml index 238fb91fa..638b3e696 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -31,7 +31,7 @@ linters: - misspell - nakedret - nolintlint - - prealloc +# - prealloc - rowserrcheck - scopelint - staticcheck diff --git a/Makefile b/Makefile index 83455ecf9..27e3287d4 100644 --- a/Makefile +++ b/Makefile @@ -169,6 +169,9 @@ check-pipeline: ## Run local CircleCI pipeline locally (sanity check) circleci local execute -c .tmp/circleci.yml --job "Unit & Integration Tests (go-latest)" @printf '$(SUCCESS)Pipeline checks pass!$(RESET)\n' +proto: + protoc -I syft/plugin/proto/ syft/plugin/proto/cataloger.proto --go_out=plugins=grpc:syft/plugin/proto/ + .PHONY: build build: $(SNAPSHOTDIR) ## Build release snapshot binaries and packages diff --git a/cmd/cmd.go b/cmd/cmd.go index 5d93443bb..8bcaa6768 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -3,6 +3,10 @@ package cmd import ( "fmt" "os" + "path" + + "github.com/adrg/xdg" + "github.com/anchore/syft/internal" "github.com/spf13/cobra" @@ -78,6 +82,18 @@ func setGlobalCliOptions() { } rootCmd.Flags().CountVarP(&cliOpts.Verbosity, "verbose", "v", "increase verbosity (-v = info, -vv = debug)") + + // plugins + defaultPluginDir := path.Join(xdg.ConfigHome, internal.ApplicationName, "plugins") + flag = "plugins.dir" + rootCmd.Flags().String( + flag, defaultPluginDir, + "plugin storage directory", + ) + if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil { + fmt.Printf("unable to bind flag '%s': %+v", flag, err) + os.Exit(1) + } } func initAppConfig() { diff --git a/go.mod b/go.mod index 5929b2ec1..9434712ad 100644 --- a/go.mod +++ b/go.mod @@ -12,11 +12,13 @@ require ( github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect github.com/dustin/go-humanize v1.0.0 github.com/go-test/deep v1.0.6 + github.com/golang/protobuf v1.4.2 github.com/google/go-containerregistry v0.1.1 // indirect github.com/google/uuid v1.1.1 github.com/gookit/color v1.2.7 github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect github.com/hashicorp/go-multierror v1.1.0 + github.com/hashicorp/go-plugin v1.3.0 github.com/hashicorp/go-version v1.2.0 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.3.1 @@ -39,6 +41,7 @@ require ( golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 // indirect golang.org/x/sys v0.0.0-20200610111108-226ff32320da // indirect google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7 // indirect + google.golang.org/grpc v1.31.1 gopkg.in/ini.v1 v1.57.0 // indirect gopkg.in/yaml.v2 v2.3.0 ) diff --git a/go.sum b/go.sum index 9c65daa48..1e1009cd5 100644 --- a/go.sum +++ b/go.sum @@ -474,12 +474,16 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8= +github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= @@ -500,6 +504,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -510,6 +516,7 @@ github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= @@ -611,6 +618,8 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= @@ -639,6 +648,8 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1 github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= @@ -923,6 +934,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1148,6 +1160,7 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1181,6 +1194,7 @@ google.golang.org/genproto v0.0.0-20200604104852-0b0486081ffb h1:ek2py5bOqzR7MR/ google.golang.org/genproto v0.0.0-20200604104852-0b0486081ffb/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7 h1:1N7l1PuXZwEK7OhHdmKQROOM75PnUjABGwvVRbLBgFk= google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1195,6 +1209,8 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/internal/config/config.go b/internal/config/config.go index 9ab861a43..261d4a01c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -28,7 +28,13 @@ type Application struct { Quiet bool `mapstructure:"quiet"` Log Logging `mapstructure:"log"` CliOptions CliOnlyOptions - CheckForAppUpdate bool `mapstructure:"check-for-app-update"` + CheckForAppUpdate bool `mapstructure:"check-for-app-update"` + Plugins Plugins `mapstructure:"plugins"` +} + +type Plugins struct { + Enabled bool `mapstructure:"enabled"` + Directory string `mapstructure:"dir"` } type Logging struct { diff --git a/syft/cataloger/apkdb/cataloger.go b/syft/cataloger/apkdb/cataloger.go index 676b9d14e..23ce1b80f 100644 --- a/syft/cataloger/apkdb/cataloger.go +++ b/syft/cataloger/apkdb/cataloger.go @@ -4,11 +4,12 @@ Package apkdb provides a concrete Cataloger implementation for Alpine DB files. package apkdb import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // Cataloger catalogs pkg.ApkPkg Package Types defined in Alpine DB files. diff --git a/syft/cataloger/bundler/cataloger.go b/syft/cataloger/bundler/cataloger.go index 3af6dbcce..8bcbe0bd3 100644 --- a/syft/cataloger/bundler/cataloger.go +++ b/syft/cataloger/bundler/cataloger.go @@ -4,11 +4,12 @@ Package bundler provides a concrete Cataloger implementation for Ruby Gemfile.lo package bundler import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // Cataloger catalogs pkg.GemPkg Package Types defined in Bundler Gemfile.lock files. diff --git a/syft/cataloger/cataloger.go b/syft/cataloger/cataloger.go index 476bcd3ab..237aa6697 100644 --- a/syft/cataloger/cataloger.go +++ b/syft/cataloger/cataloger.go @@ -6,6 +6,8 @@ catalogers defined in child packages as well as the interface definition to impl package cataloger import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/apkdb" "github.com/anchore/syft/syft/cataloger/bundler" @@ -17,7 +19,6 @@ import ( "github.com/anchore/syft/syft/cataloger/rpmdb" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // Cataloger describes behavior for an object to participate in parsing container image or file system diff --git a/syft/cataloger/common/generic_cataloger.go b/syft/cataloger/common/generic_cataloger.go index e5493547f..ee3d1c027 100644 --- a/syft/cataloger/common/generic_cataloger.go +++ b/syft/cataloger/common/generic_cataloger.go @@ -4,11 +4,12 @@ Package common provides generic utilities used by multiple catalogers. package common import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/internal/log" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // GenericCataloger implements the Catalog interface and is responsible for dispatching the proper parser function for diff --git a/syft/cataloger/dpkg/cataloger.go b/syft/cataloger/dpkg/cataloger.go index 7665a11bc..040e0682a 100644 --- a/syft/cataloger/dpkg/cataloger.go +++ b/syft/cataloger/dpkg/cataloger.go @@ -4,11 +4,12 @@ Package dpkg provides a concrete Cataloger implementation for Debian package DB package dpkg import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // Cataloger catalogs pkg.DebPkg Package Types defined in DPKG status files. diff --git a/syft/cataloger/golang/cataloger.go b/syft/cataloger/golang/cataloger.go index 9c4e1dc66..f18642ba5 100644 --- a/syft/cataloger/golang/cataloger.go +++ b/syft/cataloger/golang/cataloger.go @@ -4,11 +4,12 @@ Package golang provides a concrete Cataloger implementation for go.mod files. package golang import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // Cataloger catalogs pkg.GoModulePkg Package Types defined in go.mod files. diff --git a/syft/cataloger/java/cataloger.go b/syft/cataloger/java/cataloger.go index 84d89cda9..0f61fa0f4 100644 --- a/syft/cataloger/java/cataloger.go +++ b/syft/cataloger/java/cataloger.go @@ -4,11 +4,12 @@ Package java provides a concrete Cataloger implementation for Java archives (jar package java import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // Cataloger catalogs pkg.JavaPkg and pkg.JenkinsPluginPkg Package Types defined in java archive files. diff --git a/syft/cataloger/javascript/cataloger.go b/syft/cataloger/javascript/cataloger.go index d60f5ff93..7c61e5eb2 100644 --- a/syft/cataloger/javascript/cataloger.go +++ b/syft/cataloger/javascript/cataloger.go @@ -4,11 +4,12 @@ Package javascript provides a concrete Cataloger implementation for JavaScript e package javascript import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // Cataloger catalogs pkg.YarnPkg and pkg.NpmPkg Package Types defined in package-lock.json and yarn.lock files. diff --git a/syft/cataloger/python/cataloger.go b/syft/cataloger/python/cataloger.go index 2266803e9..c994e0556 100644 --- a/syft/cataloger/python/cataloger.go +++ b/syft/cataloger/python/cataloger.go @@ -4,11 +4,12 @@ Package python provides a concrete Cataloger implementation for Python ecosystem package python import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // Cataloger catalogs pkg.WheelPkg, pkg.EggPkg, and pkg.PythonRequirementsPkg Package Types defined in Python ecosystem files. diff --git a/syft/cataloger/rpmdb/cataloger.go b/syft/cataloger/rpmdb/cataloger.go index 91b3b1995..60bd18a2e 100644 --- a/syft/cataloger/rpmdb/cataloger.go +++ b/syft/cataloger/rpmdb/cataloger.go @@ -4,11 +4,12 @@ Package rpmdb provides a concrete Cataloger implementation for RPM "Package" DB package rpmdb import ( + "io" + "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" - "io" ) // Cataloger catalogs pkg.RpmPkg Package Types defined in RPM DB files. diff --git a/syft/plugin/cataloger_plugin.go b/syft/plugin/cataloger_plugin.go new file mode 100644 index 000000000..c092fb49b --- /dev/null +++ b/syft/plugin/cataloger_plugin.go @@ -0,0 +1,34 @@ +package plugin + +import ( + "context" + + "github.com/anchore/syft/syft/cataloger" + syftPluginGrpc "github.com/anchore/syft/syft/plugin/grpc" + "github.com/anchore/syft/syft/plugin/proto" + "github.com/hashicorp/go-plugin" + "google.golang.org/grpc" +) + +// integrity check +var _ plugin.GRPCPlugin = &CatalogerPlugin{} + +// Cataloger is the interface exposed as a plugin. +type Cataloger interface { + cataloger.Cataloger +} + +// CatalogerPlugin is the implementation of plugin.Plugin that is served/consumed. +type CatalogerPlugin struct { + plugin.NetRPCUnsupportedPlugin + Impl Cataloger +} + +func (p *CatalogerPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error { + proto.RegisterCatalogerServer(s, syftPluginGrpc.NewCatalogServer(p.Impl, broker)) + return nil +} + +func (p *CatalogerPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { + return syftPluginGrpc.NewCatalogerClient(proto.NewCatalogerClient(c), broker), nil +} diff --git a/syft/plugin/discover.go b/syft/plugin/discover.go new file mode 100644 index 000000000..fd8432d49 --- /dev/null +++ b/syft/plugin/discover.go @@ -0,0 +1,43 @@ +package plugin + +import "path/filepath" + +func Discover(dir string, pluginTypes ...Type) ([]Plugin, error) { + var err error + + if len(pluginTypes) == 0 { + pluginTypes = AllTypes + } + + if !filepath.IsAbs(dir) { + dir, err = filepath.Abs(dir) + if err != nil { + return nil, err + } + } + + var plugins []Plugin + + for _, pluginType := range pluginTypes { + // look into a sub dir named by the plugin type + searchDir := filepath.Join(dir, pluginType.String()) + + paths, err := filepath.Glob(filepath.Join(searchDir, "*")) + if err != nil { + return nil, err + } + + for _, path := range paths { + // TODO: should we use a config for some of this? + plugins = append(plugins, NewPlugin(Config{ + // TODO: should the name be org/name instead of just name? this implies changing the dir storage too + Name: filepath.Base(path), + Type: pluginType, + Command: path, + Args: nil, // TODO + Env: nil, // TODO + })) + } + } + return plugins, nil +} diff --git a/syft/plugin/grpc/cataloger_client.go b/syft/plugin/grpc/cataloger_client.go new file mode 100644 index 000000000..818d815bf --- /dev/null +++ b/syft/plugin/grpc/cataloger_client.go @@ -0,0 +1,102 @@ +package grpc + +import ( + "context" + "fmt" + "io" + "io/ioutil" + + "github.com/anchore/stereoscope/pkg/file" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/plugin/proto" + "github.com/anchore/syft/syft/scope" + "github.com/hashicorp/go-plugin" + "google.golang.org/grpc" +) + +type CatalogerClient struct { + broker *plugin.GRPCBroker + client proto.CatalogerClient +} + +func NewCatalogerClient(client proto.CatalogerClient, broker *plugin.GRPCBroker) *CatalogerClient { + return &CatalogerClient{ + broker: broker, + client: client, + } +} + +func (c *CatalogerClient) Name() string { + resp, err := c.client.Name(context.Background(), &proto.Empty{}) + if err != nil { + return fmt.Sprintf("error (%s)", err.Error()) + } + + return resp.Name +} + +func (c *CatalogerClient) SelectFiles(resolver scope.FileResolver) error { + fileResolverServer := &FileResolverServer{Impl: resolver} + + var s *grpc.Server + serverFunc := func(opts []grpc.ServerOption) *grpc.Server { + s = grpc.NewServer(opts...) + proto.RegisterFileResolverServer(s, fileResolverServer) + + return s + } + + brokerID := c.broker.NextId() + go c.broker.AcceptAndServe(brokerID, serverFunc) + + _, err := c.client.SelectFiles(context.Background(), &proto.SelectFilesRequest{ + FileResolverBrokerId: brokerID, + }) + + s.Stop() + return err +} + +func (c *CatalogerClient) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) { + var fileRefContents []*proto.FileReferenceContents + for ref, reader := range contents { + readerContents, err := ioutil.ReadAll(reader) + if err != nil { + return nil, fmt.Errorf("could not read %+v contents: %+v", ref, err) + } + fileRefContents = append(fileRefContents, &proto.FileReferenceContents{ + Id: int64(ref.ID()), + Path: string(ref.Path), + Contents: string(readerContents), + }) + } + resp, err := c.client.Catalog(context.Background(), &proto.CatalogRequest{ + Contents: fileRefContents, + }) + if err != nil { + return nil, err + } + + var result []pkg.Package + for _, p := range resp.Package { + if p != nil { + var sources []file.Reference + for _, s := range p.Source { + sources = append(sources, file.NewFileReferenceWithID(file.Path(s.Path), uint64(s.Id))) + } + // TODO: this is potentially brittle + result = append(result, pkg.Package{ + Name: p.Name, + Version: p.Version, + FoundBy: p.FoundBy, + Source: sources, + Licenses: p.Licenses, + Language: pkg.Language(p.Language), + Type: pkg.Type(p.Type), + Metadata: p.Metadata, + }) + } + } + + return result, nil +} diff --git a/syft/plugin/grpc/cataloger_server.go b/syft/plugin/grpc/cataloger_server.go new file mode 100644 index 000000000..b568307a9 --- /dev/null +++ b/syft/plugin/grpc/cataloger_server.go @@ -0,0 +1,99 @@ +package grpc + +import ( + "context" + "io" + "strings" + + "github.com/anchore/stereoscope/pkg/file" + "github.com/anchore/syft/syft/cataloger" + "github.com/anchore/syft/syft/plugin/proto" + "github.com/hashicorp/go-plugin" +) + +type CatalogerServer struct { + Impl cataloger.Cataloger + broker *plugin.GRPCBroker +} + +func NewCatalogServer(impl cataloger.Cataloger, broker *plugin.GRPCBroker) *CatalogerServer { + return &CatalogerServer{ + Impl: impl, + broker: broker, + } +} + +func (s *CatalogerServer) Name(ctx context.Context, req *proto.Empty) (*proto.NameResponse, error) { + name := s.Impl.Name() + return &proto.NameResponse{ + Name: name, + }, nil +} + +func (s *CatalogerServer) SelectFiles(ctx context.Context, req *proto.SelectFilesRequest) (*proto.SelectFilesResponse, error) { + conn, err := s.broker.Dial(req.FileResolverBrokerId) + if err != nil { + return nil, err + } + defer conn.Close() + + fileResolverClient := &FileResolverClient{proto.NewFileResolverClient(conn)} + + fileRefs := s.Impl.SelectFiles(fileResolverClient) + + var refs []*proto.FileReference + for _, ref := range fileRefs { + refs = append(refs, &proto.FileReference{ + Id: int64(ref.ID()), + Path: string(ref.Path), + }) + } + + return &proto.SelectFilesResponse{ + Files: refs, + }, nil +} + +func (s *CatalogerServer) Catalog(ctx context.Context, req *proto.CatalogRequest) (*proto.CatalogResponse, error) { + contents := make(map[file.Reference]io.Reader) + for _, f := range req.Contents { + contents[file.NewFileReferenceWithID(file.Path(f.Path), uint64(f.Id))] = strings.NewReader(f.Contents) + } + packages, err := s.Impl.Catalog(contents) + if err != nil { + return nil, err + } + + var results []proto.Package + for _, p := range packages { + var sources []*proto.FileReference + for _, s := range p.Source { + sources = append(sources, &proto.FileReference{ + Id: int64(s.ID()), + Path: string(s.Path), + }) + } + + var metadata map[string]string + if v, ok := p.Metadata.(map[string]string); ok { + metadata = v + } + + // TODO: this is potentially brittle + results = append(results, proto.Package{ + Name: p.Name, + Version: p.Version, + FoundBy: p.FoundBy, + Source: sources, + Licenses: p.Licenses, + Language: uint64(p.Language), + Type: string(p.Type), + // TODO: metadata needs to be more thoroughly thought through + Metadata: metadata, + }) + } + + return &proto.CatalogResponse{ + Package: nil, + }, nil +} diff --git a/syft/plugin/grpc/file_resolver_client.go b/syft/plugin/grpc/file_resolver_client.go new file mode 100644 index 000000000..cdc35a957 --- /dev/null +++ b/syft/plugin/grpc/file_resolver_client.go @@ -0,0 +1,46 @@ +package grpc + +import ( + "context" + + "github.com/anchore/stereoscope/pkg/file" + "github.com/anchore/syft/syft/plugin/proto" +) + +type FileResolverClient struct{ client proto.FileResolverClient } + +func (m *FileResolverClient) FilesByPath(paths ...file.Path) ([]file.Reference, error) { + var pathStrs []string + for _, p := range paths { + pathStrs = append(pathStrs, string(p)) + } + resp, err := m.client.FilesByPath(context.Background(), &proto.FileResolverRequest{ + Paths: pathStrs, + }) + if err != nil { + return nil, err + } + + var result []file.Reference + for _, ref := range resp.Files { + result = append(result, file.NewFileReferenceWithID(file.Path(ref.Path), uint64(ref.Id))) + } + + return result, err +} + +func (m *FileResolverClient) FilesByGlob(patterns ...string) ([]file.Reference, error) { + resp, err := m.client.FilesByGlob(context.Background(), &proto.FileResolverRequest{ + Paths: patterns, + }) + if err != nil { + return nil, err + } + + var result []file.Reference + for _, ref := range resp.Files { + result = append(result, file.NewFileReferenceWithID(file.Path(ref.Path), uint64(ref.Id))) + } + + return result, err +} diff --git a/syft/plugin/grpc/file_resolver_server.go b/syft/plugin/grpc/file_resolver_server.go new file mode 100644 index 000000000..87c7096ec --- /dev/null +++ b/syft/plugin/grpc/file_resolver_server.go @@ -0,0 +1,55 @@ +package grpc + +import ( + "context" + + "github.com/anchore/stereoscope/pkg/file" + "github.com/anchore/syft/syft/plugin/proto" + "github.com/anchore/syft/syft/scope" +) + +type FileResolverServer struct { + Impl scope.FileResolver +} + +func (m *FileResolverServer) FilesByPath(ctx context.Context, req *proto.FileResolverRequest) (resp *proto.FileResolverResponse, err error) { + var paths []file.Path + for _, p := range req.Paths { + paths = append(paths, file.Path(p)) + } + r, err := m.Impl.FilesByPath(paths...) + if err != nil { + return nil, err + } + + var refs []*proto.FileReference + for _, ref := range r { + refs = append(refs, &proto.FileReference{ + Id: int64(ref.ID()), + Path: string(ref.Path), + }) + } + + return &proto.FileResolverResponse{ + Files: refs, + }, nil +} + +func (m *FileResolverServer) FilesByGlob(ctx context.Context, req *proto.FileResolverRequest) (resp *proto.FileResolverResponse, err error) { + r, err := m.Impl.FilesByGlob(req.Paths...) + if err != nil { + return nil, err + } + + var refs []*proto.FileReference + for _, ref := range r { + refs = append(refs, &proto.FileReference{ + Id: int64(ref.ID()), + Path: string(ref.Path), + }) + } + + return &proto.FileResolverResponse{ + Files: refs, + }, nil +} diff --git a/syft/plugin/plugin.go b/syft/plugin/plugin.go new file mode 100644 index 000000000..12cdd0745 --- /dev/null +++ b/syft/plugin/plugin.go @@ -0,0 +1,85 @@ +package plugin + +import ( + "fmt" + "os/exec" + + "github.com/hashicorp/go-plugin" +) + +var plugins = map[int]plugin.PluginSet{ + 1: { + TypeCataloger.String(): &CatalogerPlugin{}, + }, +} + +type Config struct { + Name string + Type Type + Command string + Args []string + Env []string + //Sha256 []byte +} + +type Plugin struct { + Config Config + clientConfig *plugin.ClientConfig + client *plugin.Client +} + +func NewPlugin(config Config) Plugin { + cmd := exec.Command(config.Command, config.Args...) + cmd.Env = append(cmd.Env, config.Env...) + + //secureConfig := &plugin.SecureConfig{ + // Checksum: config.Sha256, + // Hash: sha256.New(), + //} + + clientConfig := &plugin.ClientConfig{ + HandshakeConfig: config.Type.HandshakeConfig(), + VersionedPlugins: plugins, + //SecureConfig: secureConfig, + Cmd: cmd, + AllowedProtocols: []plugin.Protocol{ + plugin.ProtocolGRPC, + }, + } + + return Plugin{ + Config: config, + clientConfig: clientConfig, + } +} + +func (p Plugin) Start() (interface{}, error) { + if p.client != nil { + return nil, fmt.Errorf("plugin already started") + } + + // start the plugin in a sub process + p.client = plugin.NewClient(p.clientConfig) + + // connect to the sub process via RPC + rpcClient, err := p.client.Client() + if err != nil { + return nil, err + } + + // fetch the plugin object meeting the requested interface + raw, err := rpcClient.Dispense(p.Config.Type.String()) + if err != nil { + return nil, err + } + + return raw, nil +} + +func (p Plugin) Stop() error { + if p.client == nil { + return fmt.Errorf("plugin has not been started") + } + p.client.Kill() + return nil +} diff --git a/syft/plugin/proto/cataloger.pb.go b/syft/plugin/proto/cataloger.pb.go new file mode 100644 index 000000000..5b25b95d6 --- /dev/null +++ b/syft/plugin/proto/cataloger.pb.go @@ -0,0 +1,841 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: cataloger.proto + +package proto + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type FileReference struct { + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FileReference) Reset() { *m = FileReference{} } +func (m *FileReference) String() string { return proto.CompactTextString(m) } +func (*FileReference) ProtoMessage() {} +func (*FileReference) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{0} +} + +func (m *FileReference) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileReference.Unmarshal(m, b) +} +func (m *FileReference) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileReference.Marshal(b, m, deterministic) +} +func (m *FileReference) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileReference.Merge(m, src) +} +func (m *FileReference) XXX_Size() int { + return xxx_messageInfo_FileReference.Size(m) +} +func (m *FileReference) XXX_DiscardUnknown() { + xxx_messageInfo_FileReference.DiscardUnknown(m) +} + +var xxx_messageInfo_FileReference proto.InternalMessageInfo + +func (m *FileReference) GetId() int64 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *FileReference) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +type FileReferenceContents struct { + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` + Contents string `protobuf:"bytes,3,opt,name=contents,proto3" json:"contents,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FileReferenceContents) Reset() { *m = FileReferenceContents{} } +func (m *FileReferenceContents) String() string { return proto.CompactTextString(m) } +func (*FileReferenceContents) ProtoMessage() {} +func (*FileReferenceContents) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{1} +} + +func (m *FileReferenceContents) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileReferenceContents.Unmarshal(m, b) +} +func (m *FileReferenceContents) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileReferenceContents.Marshal(b, m, deterministic) +} +func (m *FileReferenceContents) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileReferenceContents.Merge(m, src) +} +func (m *FileReferenceContents) XXX_Size() int { + return xxx_messageInfo_FileReferenceContents.Size(m) +} +func (m *FileReferenceContents) XXX_DiscardUnknown() { + xxx_messageInfo_FileReferenceContents.DiscardUnknown(m) +} + +var xxx_messageInfo_FileReferenceContents proto.InternalMessageInfo + +func (m *FileReferenceContents) GetId() int64 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *FileReferenceContents) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +func (m *FileReferenceContents) GetContents() string { + if m != nil { + return m.Contents + } + return "" +} + +type Empty struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Empty) Reset() { *m = Empty{} } +func (m *Empty) String() string { return proto.CompactTextString(m) } +func (*Empty) ProtoMessage() {} +func (*Empty) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{2} +} + +func (m *Empty) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Empty.Unmarshal(m, b) +} +func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Empty.Marshal(b, m, deterministic) +} +func (m *Empty) XXX_Merge(src proto.Message) { + xxx_messageInfo_Empty.Merge(m, src) +} +func (m *Empty) XXX_Size() int { + return xxx_messageInfo_Empty.Size(m) +} +func (m *Empty) XXX_DiscardUnknown() { + xxx_messageInfo_Empty.DiscardUnknown(m) +} + +var xxx_messageInfo_Empty proto.InternalMessageInfo + +type FileResolverRequest struct { + Paths []string `protobuf:"bytes,1,rep,name=paths,proto3" json:"paths,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FileResolverRequest) Reset() { *m = FileResolverRequest{} } +func (m *FileResolverRequest) String() string { return proto.CompactTextString(m) } +func (*FileResolverRequest) ProtoMessage() {} +func (*FileResolverRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{3} +} + +func (m *FileResolverRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileResolverRequest.Unmarshal(m, b) +} +func (m *FileResolverRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileResolverRequest.Marshal(b, m, deterministic) +} +func (m *FileResolverRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileResolverRequest.Merge(m, src) +} +func (m *FileResolverRequest) XXX_Size() int { + return xxx_messageInfo_FileResolverRequest.Size(m) +} +func (m *FileResolverRequest) XXX_DiscardUnknown() { + xxx_messageInfo_FileResolverRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_FileResolverRequest proto.InternalMessageInfo + +func (m *FileResolverRequest) GetPaths() []string { + if m != nil { + return m.Paths + } + return nil +} + +type FileResolverResponse struct { + Files []*FileReference `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FileResolverResponse) Reset() { *m = FileResolverResponse{} } +func (m *FileResolverResponse) String() string { return proto.CompactTextString(m) } +func (*FileResolverResponse) ProtoMessage() {} +func (*FileResolverResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{4} +} + +func (m *FileResolverResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FileResolverResponse.Unmarshal(m, b) +} +func (m *FileResolverResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FileResolverResponse.Marshal(b, m, deterministic) +} +func (m *FileResolverResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_FileResolverResponse.Merge(m, src) +} +func (m *FileResolverResponse) XXX_Size() int { + return xxx_messageInfo_FileResolverResponse.Size(m) +} +func (m *FileResolverResponse) XXX_DiscardUnknown() { + xxx_messageInfo_FileResolverResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_FileResolverResponse proto.InternalMessageInfo + +func (m *FileResolverResponse) GetFiles() []*FileReference { + if m != nil { + return m.Files + } + return nil +} + +type NameResponse struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NameResponse) Reset() { *m = NameResponse{} } +func (m *NameResponse) String() string { return proto.CompactTextString(m) } +func (*NameResponse) ProtoMessage() {} +func (*NameResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{5} +} + +func (m *NameResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NameResponse.Unmarshal(m, b) +} +func (m *NameResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NameResponse.Marshal(b, m, deterministic) +} +func (m *NameResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_NameResponse.Merge(m, src) +} +func (m *NameResponse) XXX_Size() int { + return xxx_messageInfo_NameResponse.Size(m) +} +func (m *NameResponse) XXX_DiscardUnknown() { + xxx_messageInfo_NameResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_NameResponse proto.InternalMessageInfo + +func (m *NameResponse) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type SelectFilesRequest struct { + FileResolverBrokerId uint32 `protobuf:"varint,1,opt,name=fileResolverBrokerId,proto3" json:"fileResolverBrokerId,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SelectFilesRequest) Reset() { *m = SelectFilesRequest{} } +func (m *SelectFilesRequest) String() string { return proto.CompactTextString(m) } +func (*SelectFilesRequest) ProtoMessage() {} +func (*SelectFilesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{6} +} + +func (m *SelectFilesRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SelectFilesRequest.Unmarshal(m, b) +} +func (m *SelectFilesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SelectFilesRequest.Marshal(b, m, deterministic) +} +func (m *SelectFilesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SelectFilesRequest.Merge(m, src) +} +func (m *SelectFilesRequest) XXX_Size() int { + return xxx_messageInfo_SelectFilesRequest.Size(m) +} +func (m *SelectFilesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_SelectFilesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_SelectFilesRequest proto.InternalMessageInfo + +func (m *SelectFilesRequest) GetFileResolverBrokerId() uint32 { + if m != nil { + return m.FileResolverBrokerId + } + return 0 +} + +type SelectFilesResponse struct { + Files []*FileReference `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SelectFilesResponse) Reset() { *m = SelectFilesResponse{} } +func (m *SelectFilesResponse) String() string { return proto.CompactTextString(m) } +func (*SelectFilesResponse) ProtoMessage() {} +func (*SelectFilesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{7} +} + +func (m *SelectFilesResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SelectFilesResponse.Unmarshal(m, b) +} +func (m *SelectFilesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SelectFilesResponse.Marshal(b, m, deterministic) +} +func (m *SelectFilesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SelectFilesResponse.Merge(m, src) +} +func (m *SelectFilesResponse) XXX_Size() int { + return xxx_messageInfo_SelectFilesResponse.Size(m) +} +func (m *SelectFilesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_SelectFilesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_SelectFilesResponse proto.InternalMessageInfo + +func (m *SelectFilesResponse) GetFiles() []*FileReference { + if m != nil { + return m.Files + } + return nil +} + +type Package struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + FoundBy string `protobuf:"bytes,3,opt,name=foundBy,proto3" json:"foundBy,omitempty"` + Source []*FileReference `protobuf:"bytes,4,rep,name=source,proto3" json:"source,omitempty"` + Licenses []string `protobuf:"bytes,5,rep,name=licenses,proto3" json:"licenses,omitempty"` + Language uint64 `protobuf:"varint,6,opt,name=language,proto3" json:"language,omitempty"` + Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"` + Metadata map[string]string `protobuf:"bytes,8,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Package) Reset() { *m = Package{} } +func (m *Package) String() string { return proto.CompactTextString(m) } +func (*Package) ProtoMessage() {} +func (*Package) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{8} +} + +func (m *Package) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Package.Unmarshal(m, b) +} +func (m *Package) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Package.Marshal(b, m, deterministic) +} +func (m *Package) XXX_Merge(src proto.Message) { + xxx_messageInfo_Package.Merge(m, src) +} +func (m *Package) XXX_Size() int { + return xxx_messageInfo_Package.Size(m) +} +func (m *Package) XXX_DiscardUnknown() { + xxx_messageInfo_Package.DiscardUnknown(m) +} + +var xxx_messageInfo_Package proto.InternalMessageInfo + +func (m *Package) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Package) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *Package) GetFoundBy() string { + if m != nil { + return m.FoundBy + } + return "" +} + +func (m *Package) GetSource() []*FileReference { + if m != nil { + return m.Source + } + return nil +} + +func (m *Package) GetLicenses() []string { + if m != nil { + return m.Licenses + } + return nil +} + +func (m *Package) GetLanguage() uint64 { + if m != nil { + return m.Language + } + return 0 +} + +func (m *Package) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *Package) GetMetadata() map[string]string { + if m != nil { + return m.Metadata + } + return nil +} + +type CatalogRequest struct { + Contents []*FileReferenceContents `protobuf:"bytes,1,rep,name=contents,proto3" json:"contents,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CatalogRequest) Reset() { *m = CatalogRequest{} } +func (m *CatalogRequest) String() string { return proto.CompactTextString(m) } +func (*CatalogRequest) ProtoMessage() {} +func (*CatalogRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{9} +} + +func (m *CatalogRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CatalogRequest.Unmarshal(m, b) +} +func (m *CatalogRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CatalogRequest.Marshal(b, m, deterministic) +} +func (m *CatalogRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CatalogRequest.Merge(m, src) +} +func (m *CatalogRequest) XXX_Size() int { + return xxx_messageInfo_CatalogRequest.Size(m) +} +func (m *CatalogRequest) XXX_DiscardUnknown() { + xxx_messageInfo_CatalogRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_CatalogRequest proto.InternalMessageInfo + +func (m *CatalogRequest) GetContents() []*FileReferenceContents { + if m != nil { + return m.Contents + } + return nil +} + +type CatalogResponse struct { + Package []*Package `protobuf:"bytes,1,rep,name=package,proto3" json:"package,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CatalogResponse) Reset() { *m = CatalogResponse{} } +func (m *CatalogResponse) String() string { return proto.CompactTextString(m) } +func (*CatalogResponse) ProtoMessage() {} +func (*CatalogResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_346aaad5d7f2c092, []int{10} +} + +func (m *CatalogResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CatalogResponse.Unmarshal(m, b) +} +func (m *CatalogResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CatalogResponse.Marshal(b, m, deterministic) +} +func (m *CatalogResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CatalogResponse.Merge(m, src) +} +func (m *CatalogResponse) XXX_Size() int { + return xxx_messageInfo_CatalogResponse.Size(m) +} +func (m *CatalogResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CatalogResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_CatalogResponse proto.InternalMessageInfo + +func (m *CatalogResponse) GetPackage() []*Package { + if m != nil { + return m.Package + } + return nil +} + +func init() { + proto.RegisterType((*FileReference)(nil), "proto.FileReference") + proto.RegisterType((*FileReferenceContents)(nil), "proto.FileReferenceContents") + proto.RegisterType((*Empty)(nil), "proto.Empty") + proto.RegisterType((*FileResolverRequest)(nil), "proto.FileResolverRequest") + proto.RegisterType((*FileResolverResponse)(nil), "proto.FileResolverResponse") + proto.RegisterType((*NameResponse)(nil), "proto.NameResponse") + proto.RegisterType((*SelectFilesRequest)(nil), "proto.SelectFilesRequest") + proto.RegisterType((*SelectFilesResponse)(nil), "proto.SelectFilesResponse") + proto.RegisterType((*Package)(nil), "proto.Package") + proto.RegisterMapType((map[string]string)(nil), "proto.Package.MetadataEntry") + proto.RegisterType((*CatalogRequest)(nil), "proto.CatalogRequest") + proto.RegisterType((*CatalogResponse)(nil), "proto.CatalogResponse") +} + +func init() { proto.RegisterFile("cataloger.proto", fileDescriptor_346aaad5d7f2c092) } + +var fileDescriptor_346aaad5d7f2c092 = []byte{ + // 541 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0xcb, 0x8e, 0xd3, 0x3c, + 0x14, 0x56, 0x7a, 0x4b, 0x7b, 0x7a, 0x99, 0x5f, 0x6e, 0xe7, 0x57, 0x08, 0x2c, 0xaa, 0xac, 0xca, + 0x45, 0x5d, 0x74, 0x36, 0x15, 0xb3, 0xa2, 0x65, 0x86, 0x8b, 0x04, 0x1a, 0x99, 0x05, 0x6b, 0x4f, + 0x7a, 0x5a, 0xa2, 0xa6, 0x71, 0x88, 0xdd, 0x4a, 0x79, 0x19, 0x1e, 0x83, 0x07, 0xe0, 0xc9, 0x50, + 0x6c, 0x27, 0xd4, 0x10, 0x21, 0x34, 0xab, 0xf8, 0xe4, 0xfb, 0xfc, 0x9d, 0xcf, 0xe7, 0x02, 0x17, + 0x21, 0x93, 0x2c, 0xe6, 0x3b, 0xcc, 0xe6, 0x69, 0xc6, 0x25, 0x27, 0x6d, 0xf5, 0x09, 0xae, 0x60, + 0x78, 0x1b, 0xc5, 0x48, 0x71, 0x8b, 0x19, 0x26, 0x21, 0x92, 0x11, 0x34, 0xa2, 0x8d, 0xe7, 0x4c, + 0x9d, 0x59, 0x93, 0x36, 0xa2, 0x0d, 0x21, 0xd0, 0x4a, 0x99, 0xfc, 0xe2, 0x35, 0xa6, 0xce, 0xac, + 0x47, 0xd5, 0x39, 0xf8, 0x0c, 0x97, 0xd6, 0xa5, 0x35, 0x4f, 0x24, 0x26, 0x52, 0xfc, 0xcb, 0x65, + 0xe2, 0x43, 0x37, 0x34, 0x7c, 0xaf, 0xa9, 0xfe, 0x57, 0x71, 0xe0, 0x42, 0xfb, 0xe6, 0x90, 0xca, + 0x3c, 0x78, 0x0e, 0x63, 0x9d, 0x41, 0xf0, 0xf8, 0x84, 0x19, 0xc5, 0xaf, 0x47, 0x14, 0x92, 0x4c, + 0xa0, 0x5d, 0x68, 0x08, 0xcf, 0x99, 0x36, 0x67, 0x3d, 0xaa, 0x83, 0x60, 0x05, 0x13, 0x9b, 0x2c, + 0x52, 0x9e, 0x08, 0x24, 0xcf, 0xa0, 0xbd, 0x8d, 0x62, 0xd4, 0xec, 0xfe, 0x62, 0xa2, 0x5f, 0x3e, + 0xb7, 0xac, 0x53, 0x4d, 0x09, 0x02, 0x18, 0x7c, 0x64, 0x07, 0xac, 0xee, 0x12, 0x68, 0x25, 0xec, + 0x80, 0xea, 0x2d, 0x3d, 0xaa, 0xce, 0xc1, 0x5b, 0x20, 0x9f, 0x30, 0xc6, 0x50, 0x16, 0x0a, 0xa2, + 0xf4, 0xb4, 0x80, 0xc9, 0xf6, 0x2c, 0xfb, 0x2a, 0xe3, 0x7b, 0xcc, 0xde, 0xe9, 0x2a, 0x0c, 0x69, + 0x2d, 0x16, 0xbc, 0x82, 0xb1, 0xa5, 0xf4, 0x00, 0xc3, 0x3f, 0x1a, 0xe0, 0xde, 0xb1, 0x70, 0xcf, + 0x76, 0xb5, 0x66, 0x89, 0x07, 0xee, 0x09, 0x33, 0x11, 0xf1, 0xc4, 0x54, 0xbf, 0x0c, 0x0b, 0x64, + 0xcb, 0x8f, 0xc9, 0x66, 0x95, 0x9b, 0xfa, 0x97, 0x21, 0x79, 0x01, 0x1d, 0xc1, 0x8f, 0x59, 0x88, + 0x5e, 0xeb, 0x2f, 0x06, 0x0c, 0xa7, 0x68, 0x64, 0x1c, 0x85, 0x98, 0x08, 0x14, 0x5e, 0x5b, 0xf5, + 0xa3, 0x8a, 0x15, 0xc6, 0x92, 0xdd, 0x91, 0xed, 0xd0, 0xeb, 0x4c, 0x9d, 0x59, 0x8b, 0x56, 0x71, + 0xe1, 0x56, 0xe6, 0x29, 0x7a, 0xae, 0x76, 0x5b, 0x9c, 0xc9, 0x12, 0xba, 0x07, 0x94, 0x6c, 0xc3, + 0x24, 0xf3, 0xba, 0x2a, 0xf7, 0x13, 0x93, 0xdb, 0xbc, 0x71, 0xfe, 0xc1, 0xc0, 0x37, 0x89, 0xcc, + 0x72, 0x5a, 0xb1, 0xfd, 0x6b, 0x18, 0x5a, 0x10, 0xf9, 0x0f, 0x9a, 0x7b, 0xcc, 0x4d, 0x2d, 0x8a, + 0x63, 0x31, 0x35, 0x27, 0x16, 0x1f, 0xd1, 0x14, 0x42, 0x07, 0x2f, 0x1b, 0x4b, 0x27, 0x78, 0x0f, + 0xa3, 0xb5, 0xde, 0x8b, 0xb2, 0x9b, 0xcb, 0xb3, 0xe9, 0x74, 0x2c, 0x23, 0xb5, 0x13, 0x7f, 0x36, + 0xbb, 0xd7, 0x70, 0x51, 0x69, 0x99, 0x7e, 0xce, 0xc0, 0x4d, 0xb5, 0x7d, 0xa3, 0x35, 0xb2, 0x1f, + 0x45, 0x4b, 0x78, 0xf1, 0xdd, 0x81, 0xde, 0xba, 0xdc, 0x50, 0xf2, 0x14, 0x5a, 0xc5, 0x30, 0x92, + 0x81, 0xa1, 0xab, 0x9d, 0xf0, 0xc7, 0x26, 0xb2, 0xe6, 0xf4, 0x35, 0xf4, 0xcf, 0x26, 0x89, 0x3c, + 0x32, 0x9c, 0x3f, 0xe7, 0xd4, 0xf7, 0xeb, 0x20, 0xa3, 0xb2, 0x04, 0xd7, 0x64, 0x27, 0x97, 0x86, + 0x66, 0xd7, 0xc5, 0xff, 0xff, 0xf7, 0xdf, 0xfa, 0xe6, 0xe2, 0x9b, 0x03, 0x83, 0xf3, 0xe5, 0x23, + 0xb7, 0xd0, 0x57, 0xda, 0xab, 0xfc, 0x4e, 0x6d, 0xbb, 0x55, 0x3d, 0x6b, 0x9b, 0xfd, 0xc7, 0xb5, + 0x98, 0xb1, 0xf4, 0x4b, 0xe7, 0x4d, 0xcc, 0xef, 0x1f, 0xac, 0x73, 0xdf, 0x51, 0xd8, 0xd5, 0xcf, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x6e, 0xfe, 0x04, 0x3e, 0x01, 0x05, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// CatalogerClient is the client API for Cataloger service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type CatalogerClient interface { + Name(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*NameResponse, error) + SelectFiles(ctx context.Context, in *SelectFilesRequest, opts ...grpc.CallOption) (*SelectFilesResponse, error) + Catalog(ctx context.Context, in *CatalogRequest, opts ...grpc.CallOption) (*CatalogResponse, error) +} + +type catalogerClient struct { + cc grpc.ClientConnInterface +} + +func NewCatalogerClient(cc grpc.ClientConnInterface) CatalogerClient { + return &catalogerClient{cc} +} + +func (c *catalogerClient) Name(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*NameResponse, error) { + out := new(NameResponse) + err := c.cc.Invoke(ctx, "/proto.Cataloger/Name", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *catalogerClient) SelectFiles(ctx context.Context, in *SelectFilesRequest, opts ...grpc.CallOption) (*SelectFilesResponse, error) { + out := new(SelectFilesResponse) + err := c.cc.Invoke(ctx, "/proto.Cataloger/SelectFiles", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *catalogerClient) Catalog(ctx context.Context, in *CatalogRequest, opts ...grpc.CallOption) (*CatalogResponse, error) { + out := new(CatalogResponse) + err := c.cc.Invoke(ctx, "/proto.Cataloger/Catalog", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// CatalogerServer is the server API for Cataloger service. +type CatalogerServer interface { + Name(context.Context, *Empty) (*NameResponse, error) + SelectFiles(context.Context, *SelectFilesRequest) (*SelectFilesResponse, error) + Catalog(context.Context, *CatalogRequest) (*CatalogResponse, error) +} + +// UnimplementedCatalogerServer can be embedded to have forward compatible implementations. +type UnimplementedCatalogerServer struct { +} + +func (*UnimplementedCatalogerServer) Name(ctx context.Context, req *Empty) (*NameResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Name not implemented") +} +func (*UnimplementedCatalogerServer) SelectFiles(ctx context.Context, req *SelectFilesRequest) (*SelectFilesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SelectFiles not implemented") +} +func (*UnimplementedCatalogerServer) Catalog(ctx context.Context, req *CatalogRequest) (*CatalogResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Catalog not implemented") +} + +func RegisterCatalogerServer(s *grpc.Server, srv CatalogerServer) { + s.RegisterService(&_Cataloger_serviceDesc, srv) +} + +func _Cataloger_Name_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CatalogerServer).Name(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.Cataloger/Name", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CatalogerServer).Name(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _Cataloger_SelectFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SelectFilesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CatalogerServer).SelectFiles(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.Cataloger/SelectFiles", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CatalogerServer).SelectFiles(ctx, req.(*SelectFilesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Cataloger_Catalog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CatalogRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CatalogerServer).Catalog(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.Cataloger/Catalog", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CatalogerServer).Catalog(ctx, req.(*CatalogRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Cataloger_serviceDesc = grpc.ServiceDesc{ + ServiceName: "proto.Cataloger", + HandlerType: (*CatalogerServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Name", + Handler: _Cataloger_Name_Handler, + }, + { + MethodName: "SelectFiles", + Handler: _Cataloger_SelectFiles_Handler, + }, + { + MethodName: "Catalog", + Handler: _Cataloger_Catalog_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "cataloger.proto", +} + +// FileResolverClient is the client API for FileResolver service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type FileResolverClient interface { + FilesByPath(ctx context.Context, in *FileResolverRequest, opts ...grpc.CallOption) (*FileResolverResponse, error) + FilesByGlob(ctx context.Context, in *FileResolverRequest, opts ...grpc.CallOption) (*FileResolverResponse, error) +} + +type fileResolverClient struct { + cc grpc.ClientConnInterface +} + +func NewFileResolverClient(cc grpc.ClientConnInterface) FileResolverClient { + return &fileResolverClient{cc} +} + +func (c *fileResolverClient) FilesByPath(ctx context.Context, in *FileResolverRequest, opts ...grpc.CallOption) (*FileResolverResponse, error) { + out := new(FileResolverResponse) + err := c.cc.Invoke(ctx, "/proto.FileResolver/FilesByPath", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fileResolverClient) FilesByGlob(ctx context.Context, in *FileResolverRequest, opts ...grpc.CallOption) (*FileResolverResponse, error) { + out := new(FileResolverResponse) + err := c.cc.Invoke(ctx, "/proto.FileResolver/FilesByGlob", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// FileResolverServer is the server API for FileResolver service. +type FileResolverServer interface { + FilesByPath(context.Context, *FileResolverRequest) (*FileResolverResponse, error) + FilesByGlob(context.Context, *FileResolverRequest) (*FileResolverResponse, error) +} + +// UnimplementedFileResolverServer can be embedded to have forward compatible implementations. +type UnimplementedFileResolverServer struct { +} + +func (*UnimplementedFileResolverServer) FilesByPath(ctx context.Context, req *FileResolverRequest) (*FileResolverResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FilesByPath not implemented") +} +func (*UnimplementedFileResolverServer) FilesByGlob(ctx context.Context, req *FileResolverRequest) (*FileResolverResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method FilesByGlob not implemented") +} + +func RegisterFileResolverServer(s *grpc.Server, srv FileResolverServer) { + s.RegisterService(&_FileResolver_serviceDesc, srv) +} + +func _FileResolver_FilesByPath_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FileResolverRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FileResolverServer).FilesByPath(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.FileResolver/FilesByPath", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FileResolverServer).FilesByPath(ctx, req.(*FileResolverRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _FileResolver_FilesByGlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FileResolverRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FileResolverServer).FilesByGlob(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.FileResolver/FilesByGlob", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FileResolverServer).FilesByGlob(ctx, req.(*FileResolverRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _FileResolver_serviceDesc = grpc.ServiceDesc{ + ServiceName: "proto.FileResolver", + HandlerType: (*FileResolverServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "FilesByPath", + Handler: _FileResolver_FilesByPath_Handler, + }, + { + MethodName: "FilesByGlob", + Handler: _FileResolver_FilesByGlob_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "cataloger.proto", +} diff --git a/syft/plugin/proto/cataloger.proto b/syft/plugin/proto/cataloger.proto new file mode 100755 index 000000000..294654ab0 --- /dev/null +++ b/syft/plugin/proto/cataloger.proto @@ -0,0 +1,67 @@ +syntax = "proto3"; +package proto; + +message FileReference { + int64 id = 1; + string path = 2; +} + +message FileReferenceContents { + int64 id = 1; + string path = 2; + string contents = 3; +} + +message Empty { +} + +message FileResolverRequest { + repeated string paths = 1; +} + +message FileResolverResponse { + repeated FileReference files = 1; +} + +message NameResponse { + string name = 1; +} + +message SelectFilesRequest { + uint32 fileResolverBrokerId = 1; +} + +message SelectFilesResponse { + repeated FileReference files = 1; +} + +message Package { + string name = 1; + string version = 2; + string foundBy = 3; + repeated FileReference source = 4; + repeated string licenses = 5; + uint64 language = 6; + string type = 7; + map metadata = 8; +} + +message CatalogRequest { + repeated FileReferenceContents contents = 1; +} + +message CatalogResponse { + repeated Package package = 1; +} + +service Cataloger { + rpc Name(Empty) returns (NameResponse); + rpc SelectFiles(SelectFilesRequest) returns (SelectFilesResponse); + rpc Catalog(CatalogRequest) returns (CatalogResponse); +} + +service FileResolver { + rpc FilesByPath(FileResolverRequest) returns (FileResolverResponse); + rpc FilesByGlob(FileResolverRequest) returns (FileResolverResponse); +} + diff --git a/syft/plugin/type.go b/syft/plugin/type.go new file mode 100644 index 000000000..6164d3f8e --- /dev/null +++ b/syft/plugin/type.go @@ -0,0 +1,49 @@ +package plugin + +import ( + "fmt" + + "github.com/hashicorp/go-plugin" +) + +var AllTypes = []Type{ + TypeCataloger, +} + +type Type uint64 + +const ( + TypeUnknown Type = iota + TypeCataloger +) + +func (p Type) String() string { + switch p { + case TypeCataloger: + return "cataloger" + default: + return "unknown" + } +} + +func (p Type) HandshakeConfig() plugin.HandshakeConfig { + switch p { + case TypeCataloger: + return plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "SYFT_CATALOGER_PLUGIN", + MagicCookieValue: "0f86cc7f-6f97-410e-a844-087cd12e36e3", + } + default: + panic(fmt.Errorf("plugin type unsupported")) + } +} + +func ParseType(pluginType string) Type { + switch pluginType { + case "cataloger": + return TypeCataloger + default: + return TypeUnknown + } +} diff --git a/syft/scope/resolvers/directory_resolver.go b/syft/scope/resolvers/directory_resolver.go index 0e25edcc0..59046c280 100644 --- a/syft/scope/resolvers/directory_resolver.go +++ b/syft/scope/resolvers/directory_resolver.go @@ -2,12 +2,13 @@ package resolvers import ( "fmt" - "github.com/anchore/stereoscope/pkg/file" - "github.com/anchore/syft/internal/log" - "github.com/bmatcuk/doublestar" "io" "os" "path" + + "github.com/anchore/stereoscope/pkg/file" + "github.com/anchore/syft/internal/log" + "github.com/bmatcuk/doublestar" ) // DirectoryResolver implements path and content access for the directory data source.