mirror of
https://github.com/anchore/syft.git
synced 2026-10-13 06:37:22 +02:00
Compare commits
22
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b81c87d18 | ||
|
|
9bd9dad76c | ||
|
|
6d9f9a9b3b | ||
|
|
50cb5612d0 | ||
|
|
080f010746 | ||
|
|
f4502fc824 | ||
|
|
03378e976c | ||
|
|
576fbc898b | ||
|
|
49800b6747 | ||
|
|
c46d004a3b | ||
|
|
3d91a66536 | ||
|
|
45b5cab49a | ||
|
|
1866949eff | ||
|
|
0567206b38 | ||
|
|
f3076c3905 | ||
|
|
b467964044 | ||
|
|
e26627d8b6 | ||
|
|
80ee18d20b | ||
|
|
ef64a6f206 | ||
|
|
22dfcb2d0b | ||
|
|
329b080a37 | ||
|
|
11334b632e |
@@ -104,15 +104,15 @@ jobs:
|
||||
|
||||
- restore_cache:
|
||||
keys:
|
||||
- syft-integration-test-tar-cache-{{ checksum "test/integration/test-fixtures/tar-cache.fingerprint" }}
|
||||
- syft-integration-test-cache-{{ checksum "test/integration/test-fixtures/cache.fingerprint" }}
|
||||
- run:
|
||||
name: run integration tests
|
||||
command: make integration
|
||||
|
||||
- save_cache:
|
||||
key: syft-integration-test-tar-cache-{{ checksum "test/integration/test-fixtures/tar-cache.fingerprint" }}
|
||||
key: syft-integration-test-cache-{{ checksum "test/integration/test-fixtures/cache.fingerprint" }}
|
||||
paths:
|
||||
- "test/integration/test-fixtures/tar-cache"
|
||||
- "test/integration/test-fixtures/cache"
|
||||
|
||||
workflows:
|
||||
# Note: changing this workflow name requires making the same update in the .github/workflows/release.yaml pipeline
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
git fetch origin main
|
||||
git merge-base --is-ancestor ${GITHUB_REF##*/} origin/main && echo "${GITHUB_REF##*/} is a commit on main!"
|
||||
|
||||
- name: Check static anaylysis, unit, and integration test results
|
||||
- name: Check static analysis, unit, and integration test results
|
||||
uses: fountainhead/action-wait-for-check@v1.0.0
|
||||
id: sa-unit-int
|
||||
with:
|
||||
@@ -123,6 +123,15 @@ jobs:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
|
||||
|
||||
# - uses: 8398a7/action-slack@v3
|
||||
# with:
|
||||
# status: ${{ job.status }}
|
||||
# fields: repo,workflow,action,eventName
|
||||
# text: "A new Syft release is ready to be (manually) published from https://github.com/anchore/syft/releases"
|
||||
# env:
|
||||
# SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
|
||||
# if: ${{ success() }}
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: artifacts
|
||||
|
||||
+1
-1
@@ -31,6 +31,7 @@ linters:
|
||||
- misspell
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- rowserrcheck
|
||||
- scopelint
|
||||
- staticcheck
|
||||
@@ -54,6 +55,5 @@ linters:
|
||||
# - lll # without a way to specify per-line exception cases, this is not usable
|
||||
# - maligned # this is an excellent linter, but tricky to optimize and we are not sensitive to memory layout optimizations
|
||||
# - nestif
|
||||
# - prealloc # this unnecessarily requires preallocations for slices
|
||||
# - testpackage
|
||||
# - wsl
|
||||
@@ -27,6 +27,10 @@ ifeq "$(strip $(VERSION))" ""
|
||||
override VERSION = $(shell git describe --always --tags --dirty)
|
||||
endif
|
||||
|
||||
# used to generate the changelog from the second to last tag to the current tag (used in the release pipeline when the release tag is in place)
|
||||
LAST_TAG := $(shell git describe --abbrev=0 --tags $(shell git rev-list --tags --max-count=1))
|
||||
SECOND_TO_LAST_TAG := $(shell git describe --abbrev=0 --tags $(shell git rev-list --tags --skip=1 --max-count=1))
|
||||
|
||||
## Variable assertions
|
||||
|
||||
ifndef TEMPDIR
|
||||
@@ -130,7 +134,7 @@ integration: ## Run integration tests
|
||||
|
||||
# note: this is used by CI to determine if the integration test fixture cache (docker image tars) should be busted
|
||||
integration-fingerprint:
|
||||
find test/integration/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/integration/test-fixtures/tar-cache.fingerprint
|
||||
find test/integration/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/integration/test-fixtures/cache.fingerprint
|
||||
|
||||
.PHONY: java-packages-fingerprint
|
||||
java-packages-fingerprint:
|
||||
@@ -157,7 +161,7 @@ generate-json-schema: clean-json-schema-examples integration ## Generate a new j
|
||||
|
||||
.PHONY: clear-test-cache
|
||||
clear-test-cache: ## Delete all test cache (built docker image tars)
|
||||
find . -type f -wholename "**/test-fixtures/tar-cache/*.tar" -delete
|
||||
find . -type f -wholename "**/test-fixtures/cache/*.tar" -delete
|
||||
|
||||
.PHONY: check-pipeline
|
||||
check-pipeline: ## Run local CircleCI pipeline locally (sanity check)
|
||||
@@ -169,9 +173,6 @@ 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
|
||||
|
||||
@@ -229,32 +230,50 @@ acceptance-test-rpm-package-install: $(SNAPSHOTDIR)
|
||||
$(ACC_TEST_IMAGE) \
|
||||
$(RESULTSDIR)
|
||||
|
||||
.PHONY: changlog
|
||||
changelog:
|
||||
mkdir -p $(DISTDIR)
|
||||
.PHONY: changlog-release
|
||||
changelog-release:
|
||||
@echo "Last tag: $(SECOND_TO_LAST_TAG)"
|
||||
@echo "Current tag: $(VERSION)"
|
||||
@docker run -i --rm \
|
||||
-v "$(shell pwd)":/usr/local/src/your-app ferrarimarco/github-changelog-generator \
|
||||
--user anchore \
|
||||
--project $(BIN) \
|
||||
-t ${GITHUB_TOKEN} \
|
||||
--exclude-labels 'duplicate,question,invalid,wontfix,size:small,size:medium,size:large,size:x-large' \
|
||||
--no-pr-wo-labels \
|
||||
--no-issues-wo-labels \
|
||||
--since-tag $(SECOND_TO_LAST_TAG)
|
||||
|
||||
.PHONY: changelog-unreleased
|
||||
changelog-unreleased: ## show the current changelog that will be produced on the next release (note: requires GITHUB_TOKEN set)
|
||||
@docker run -it --rm \
|
||||
-v "$(shell pwd)":/usr/local/src/your-app ferrarimarco/github-changelog-generator \
|
||||
--user anchore \
|
||||
--project $(BIN) \
|
||||
-t ${GITHUB_TOKEN} \
|
||||
--no-pr-wo-labels \
|
||||
--no-issues-wo-labels \
|
||||
--unreleased-only \
|
||||
--future-release $(VERSION)
|
||||
--exclude-labels 'duplicate,question,invalid,wontfix,size:small,size:medium,size:large,size:x-large' \
|
||||
--since-tag $(LAST_TAG)
|
||||
|
||||
@printf '\n$(BOLD)$(CYAN)Unreleased Changes (closed PRs and issues will not be in the final changelog)$(RESET)\n'
|
||||
|
||||
@docker run -it --rm \
|
||||
-v $(shell pwd)/CHANGELOG.md:/CHANGELOG.md \
|
||||
rawkode/mdv \
|
||||
-t 696.6153 \
|
||||
/CHANGELOG.md
|
||||
|
||||
.PHONY: release
|
||||
release: clean-dist changelog ## Build and publish final binaries and packages
|
||||
release: clean-dist changelog-release ## Build and publish final binaries and packages
|
||||
$(call title,Publishing release artifacts)
|
||||
# create a config with the dist dir overridden
|
||||
echo "dist: $(DISTDIR)" > $(TEMPDIR)/goreleaser.yaml
|
||||
cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml
|
||||
|
||||
# release
|
||||
BUILD_GIT_TREE_STATE=$(GITTREESTATE) \
|
||||
$(TEMPDIR)/goreleaser \
|
||||
bash -c "BUILD_GIT_TREE_STATE=$(GITTREESTATE) $(TEMPDIR)/goreleaser \
|
||||
--rm-dist \
|
||||
--config $(TEMPDIR)/goreleaser.yaml \
|
||||
--release-notes <(cat CHANGELOG.md)
|
||||
--release-notes <(cat CHANGELOG.md)"
|
||||
|
||||
# verify checksum signatures
|
||||
.github/scripts/verify-signature.sh "$(DISTDIR)"
|
||||
|
||||
@@ -13,12 +13,13 @@ A CLI tool and go library for generating a Software Bill of Materials (SBOM) fro
|
||||
- Catalog container images and filesystems to discover packages and libraries.
|
||||
- Supports packages and libraries from various ecosystems (APK, DEB, RPM, Ruby Bundles, Python Wheel/Egg/requirements.txt, JavaScript NPM/Yarn, Java JAR/EAR/WAR, Jenkins plugins JPI/HPI, Go modules)
|
||||
- Linux distribution identification (supports Alpine, BusyBox, CentOS/RedHat, Debian/Ubuntu flavored distributions)
|
||||
- Supports Docker and OCI image formats
|
||||
|
||||
> :warning: **This is pre-release software** and it may not work as expected. If you encounter an issue, please [let us know using the issue tracker](https://github.com/anchore/syft/issues).
|
||||
|
||||
## Getting started
|
||||
|
||||
To generate an SBOM for an image:
|
||||
To generate an SBOM for a Docker or OCI image:
|
||||
```
|
||||
syft <image>
|
||||
```
|
||||
@@ -32,19 +33,24 @@ syft <image> --scope all-layers
|
||||
|
||||
Syft can generate a SBOM from a variety of sources:
|
||||
```
|
||||
# catalog a docker image tar (from the result of "docker image save ... -o image.tar" command)
|
||||
syft docker-archive://path/to/image.tar
|
||||
# catalog a container image archive (from the result of `docker image save ...`, `podman save ...`, or `skopeo copy` commands)
|
||||
syft path/to/image.tar
|
||||
|
||||
# catalog a directory
|
||||
syft dir://path/to/dir
|
||||
syft path/to/dir
|
||||
```
|
||||
|
||||
By default Syft shows a summary table, however, more detailed `text` and `json` formats are also available.
|
||||
The output format for Syft is configurable as well:
|
||||
```
|
||||
syft <image> -o json
|
||||
syft <image> -o text
|
||||
syft <image> -o <format>
|
||||
```
|
||||
|
||||
Where the `format`s available are:
|
||||
- `json`: Use this to get as much information out of Syft as possible!
|
||||
- `text`: A row-oriented, human-and-machine-friendly output.
|
||||
- `cyclonedx`: A XML report conforming to the [CycloneDX 1.2](https://cyclonedx.org/) specification.
|
||||
- `table`: A columnar summary (default).
|
||||
|
||||
## Installation
|
||||
|
||||
**Recommended**
|
||||
|
||||
+1
-17
@@ -3,10 +3,6 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/anchore/syft/internal"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
@@ -82,18 +78,6 @@ func setGlobalCliOptions() {
|
||||
}
|
||||
|
||||
rootCmd.Flags().CountVarP(&cliOpts.Verbosity, "verbose", "v", "increase verbosity (-v = info, -vv = debug)")
|
||||
|
||||
// plugins
|
||||
defaultPluginDir := path.Join(xdg.CacheHome, 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() {
|
||||
@@ -117,7 +101,7 @@ func initLogging() {
|
||||
logWrapper := logger.NewLogrusLogger(cfg)
|
||||
syft.SetLogger(logWrapper)
|
||||
stereoscope.SetLogger(&logger.LogrusNestedLogger{
|
||||
Logger: logWrapper.Logger.WithField("from-lib", "stereoscope"),
|
||||
Logger: logWrapper.Logger.WithField("from-lib", "steroscope"),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// completionCmd represents the completion command
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "completion [bash|zsh|fish]",
|
||||
Short: "Generate a shell completion for Syft (listing local docker images)",
|
||||
Long: `To load completions (docker image list):
|
||||
|
||||
Bash:
|
||||
|
||||
$ source <(syft completion bash)
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
Linux:
|
||||
$ syft completion bash > /etc/bash_completion.d/syft
|
||||
MacOS:
|
||||
$ syft completion bash > /usr/local/etc/bash_completion.d/syft
|
||||
|
||||
Zsh:
|
||||
|
||||
# If shell completion is not already enabled in your environment you will need
|
||||
# to enable it. You can execute the following once:
|
||||
|
||||
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
$ syft completion zsh > "${fpath[1]}/_syft"
|
||||
|
||||
# You will need to start a new shell for this setup to take effect.
|
||||
|
||||
Fish:
|
||||
|
||||
$ syft completion fish | source
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
$ syft completion fish > ~/.config/fish/completions/syft.fish
|
||||
`,
|
||||
DisableFlagsInUseLine: true,
|
||||
ValidArgs: []string{"bash", "zsh", "fish"},
|
||||
Args: cobra.ExactValidArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
switch args[0] {
|
||||
case "bash":
|
||||
err = cmd.Root().GenBashCompletion(os.Stdout)
|
||||
case "zsh":
|
||||
err = cmd.Root().GenZshCompletion(os.Stdout)
|
||||
case "fish":
|
||||
err = cmd.Root().GenFishCompletion(os.Stdout, true)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(completionCmd)
|
||||
}
|
||||
+56
-15
@@ -1,8 +1,10 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
@@ -12,6 +14,9 @@ import (
|
||||
"github.com/anchore/syft/syft"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/presenter"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
)
|
||||
@@ -21,10 +26,15 @@ var rootCmd = &cobra.Command{
|
||||
Short: "A tool for generating a Software Bill Of Materials (SBOM) from container images and filesystems",
|
||||
Long: internal.Tprintf(`
|
||||
Supports the following image sources:
|
||||
{{.appName}} yourrepo/yourimage:tag defaults to using images from a docker daemon
|
||||
{{.appName}} docker://yourrepo/yourimage:tag explicitly use the docker daemon
|
||||
{{.appName}} tar://path/to/yourimage.tar use a tarball from disk
|
||||
{{.appName}} dir://path/to/yourproject read directly from a path in disk
|
||||
{{.appName}} yourrepo/yourimage:tag defaults to using images from a Docker daemon
|
||||
{{.appName}} path/to/yourproject a Docker tar, OCI tar, OCI directory, or generic filesystem directory
|
||||
|
||||
You can also explicitly specify the scheme to use:
|
||||
{{.appName}} docker:yourrepo/yourimage:tag explicitly use the Docker daemon
|
||||
{{.appName}} docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
|
||||
{{.appName}} oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Podman or otherwise)
|
||||
{{.appName}} oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
|
||||
{{.appName}} dir:path/to/yourproject read directly from a path on disk (any directory)
|
||||
`, map[string]interface{}{
|
||||
"appName": internal.ApplicationName,
|
||||
}),
|
||||
@@ -44,6 +54,20 @@ Supports the following image sources:
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
// Since we use ValidArgsFunction, Cobra will call this AFTER having parsed all flags and arguments provided
|
||||
dockerImageRepoTags, err := ListLocalDockerImages(toComplete)
|
||||
if err != nil {
|
||||
// Indicates that an error occurred and completions should be ignored
|
||||
return []string{"completion failed"}, cobra.ShellCompDirectiveError
|
||||
}
|
||||
if len(dockerImageRepoTags) == 0 {
|
||||
return []string{"no docker images found"}, cobra.ShellCompDirectiveError
|
||||
}
|
||||
// ShellCompDirectiveDefault indicates that the shell will perform its default behavior after completions have
|
||||
// been provided (without implying other possible directives)
|
||||
return dockerImageRepoTags, cobra.ShellCompDirectiveDefault
|
||||
},
|
||||
}
|
||||
|
||||
func startWorker(userInput string) <-chan error {
|
||||
@@ -68,17 +92,7 @@ func startWorker(userInput string) <-chan error {
|
||||
}
|
||||
}
|
||||
|
||||
config := syft.Config{
|
||||
PluginDirectory: appConfig.Plugins.Directory,
|
||||
}
|
||||
|
||||
client, err := syft.NewClient(config)
|
||||
if err != nil {
|
||||
errs <- fmt.Errorf("could not initialize syft: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
catalog, scope, distro, err := client.Catalog(userInput, appConfig.ScopeOpt)
|
||||
catalog, scope, distro, err := syft.Catalog(userInput, appConfig.ScopeOpt)
|
||||
if err != nil {
|
||||
errs <- fmt.Errorf("failed to catalog input: %+v", err)
|
||||
return
|
||||
@@ -98,3 +112,30 @@ func doRunCmd(_ *cobra.Command, args []string) error {
|
||||
ux := ui.Select(appConfig.CliOptions.Verbosity > 0, appConfig.Quiet)
|
||||
return ux(errs, eventSubscription)
|
||||
}
|
||||
|
||||
func ListLocalDockerImages(prefix string) ([]string, error) {
|
||||
var repoTags = make([]string, 0)
|
||||
ctx := context.Background()
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
if err != nil {
|
||||
return repoTags, err
|
||||
}
|
||||
|
||||
// Only want to return tagged images
|
||||
imageListArgs := filters.NewArgs()
|
||||
imageListArgs.Add("dangling", "false")
|
||||
images, err := cli.ImageList(ctx, types.ImageListOptions{All: false, Filters: imageListArgs})
|
||||
if err != nil {
|
||||
return repoTags, err
|
||||
}
|
||||
|
||||
for _, image := range images {
|
||||
// image may have multiple tags
|
||||
for _, tag := range image.RepoTags {
|
||||
if strings.HasPrefix(tag, prefix) {
|
||||
repoTags = append(repoTags, tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
return repoTags, nil
|
||||
}
|
||||
|
||||
+39
-12
@@ -1,14 +1,19 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/presenter"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var showVerboseVersionInfo bool
|
||||
var outputFormat string
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
@@ -18,22 +23,44 @@ var versionCmd = &cobra.Command{
|
||||
|
||||
func init() {
|
||||
versionCmd.Flags().BoolVarP(&showVerboseVersionInfo, "verbose", "v", false, "show additional version information")
|
||||
|
||||
versionCmd.Flags().StringVarP(&outputFormat, "output", "o", string(presenter.TextPresenter), "format to show version information (available=[text, json])")
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
|
||||
func printVersion(_ *cobra.Command, _ []string) {
|
||||
versionInfo := version.FromBuild()
|
||||
if showVerboseVersionInfo {
|
||||
fmt.Println("Application: ", internal.ApplicationName)
|
||||
fmt.Println("Version: ", versionInfo.Version)
|
||||
fmt.Println("BuildDate: ", versionInfo.BuildDate)
|
||||
fmt.Println("GitCommit: ", versionInfo.GitCommit)
|
||||
fmt.Println("GitTreeState: ", versionInfo.GitTreeState)
|
||||
fmt.Println("Platform: ", versionInfo.Platform)
|
||||
fmt.Println("GoVersion: ", versionInfo.GoVersion)
|
||||
fmt.Println("Compiler: ", versionInfo.Compiler)
|
||||
} else {
|
||||
fmt.Printf("%s %s\n", internal.ApplicationName, versionInfo.Version)
|
||||
|
||||
switch outputFormat {
|
||||
case "text":
|
||||
if showVerboseVersionInfo {
|
||||
fmt.Println("Application: ", internal.ApplicationName)
|
||||
fmt.Println("Version: ", versionInfo.Version)
|
||||
fmt.Println("BuildDate: ", versionInfo.BuildDate)
|
||||
fmt.Println("GitCommit: ", versionInfo.GitCommit)
|
||||
fmt.Println("GitTreeState: ", versionInfo.GitTreeState)
|
||||
fmt.Println("Platform: ", versionInfo.Platform)
|
||||
fmt.Println("GoVersion: ", versionInfo.GoVersion)
|
||||
fmt.Println("Compiler: ", versionInfo.Compiler)
|
||||
} else {
|
||||
fmt.Printf("%s %s\n", internal.ApplicationName, versionInfo.Version)
|
||||
}
|
||||
case "json":
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", " ")
|
||||
err := enc.Encode(&struct {
|
||||
version.Version
|
||||
Application string `json:"application"`
|
||||
}{
|
||||
Version: versionInfo,
|
||||
Application: internal.ApplicationName,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("failed to show version information: %+v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
default:
|
||||
fmt.Printf("unsupported output format: %s\n", outputFormat)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,21 +5,16 @@ go 1.14
|
||||
require (
|
||||
github.com/adrg/xdg v0.2.1
|
||||
github.com/anchore/go-rpmdb v0.0.0-20200811175839-cbc751c28e8e
|
||||
github.com/anchore/go-testutils v0.0.0-20200624184116-66aa578126db
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/stereoscope v0.0.0-20200903223322-a3806f515470
|
||||
github.com/anchore/stereoscope v0.0.0-20200925184903-c82da54e98fe
|
||||
github.com/bmatcuk/doublestar v1.3.1
|
||||
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect
|
||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
|
||||
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-hclog v0.14.1
|
||||
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
|
||||
@@ -29,7 +24,8 @@ require (
|
||||
github.com/rogpeppe/go-internal v1.5.2
|
||||
github.com/sergi/go-diff v1.1.0
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/afero v1.2.2
|
||||
github.com/spf13/cobra v1.0.1-0.20200909172742-8a63648dd905
|
||||
github.com/spf13/viper v1.7.0
|
||||
github.com/wagoodman/go-partybus v0.0.0-20200526224238-eb215533f07d
|
||||
github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240
|
||||
@@ -37,11 +33,5 @@ require (
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
|
||||
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
|
||||
)
|
||||
|
||||
@@ -104,10 +104,10 @@ github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvo
|
||||
github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
||||
github.com/Microsoft/hcsshim v0.8.9 h1:VrfodqvztU8YSOvygU+DN1BGaSGxmrNfqOv5oOuX2Bk=
|
||||
github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab h1:9pygWVFqbY9lPxM0peffumuVDyMuIMzNLyO9uFjJuQo=
|
||||
github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
|
||||
github.com/Microsoft/hcsshim v0.8.10 h1:k5wTrpnVU2/xv8ZuzGkbXVd3js5zJ8RnumPo5RxiIxU=
|
||||
github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3HV0OhsddkmM=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us=
|
||||
@@ -126,13 +126,12 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/anchore/go-rpmdb v0.0.0-20200811175839-cbc751c28e8e h1:kty6r0R2JeaNPeWKSYDC+HW3hkqwFh4PP5TQ8pUPYFw=
|
||||
github.com/anchore/go-rpmdb v0.0.0-20200811175839-cbc751c28e8e/go.mod h1:iYuIG0Nai8dR0ri3LhZQKUyO1loxUWAGvoWhXDmjy1A=
|
||||
github.com/anchore/go-testutils v0.0.0-20200624184116-66aa578126db h1:LWKezJnFTFxNkZ4MzajVf+YWvJS0+7hwFr59u6SS7cw=
|
||||
github.com/anchore/go-testutils v0.0.0-20200624184116-66aa578126db/go.mod h1:D3rc2L/q4Hcp9eeX6AIJH4Q+kPjOtJCFhG9za90j+nU=
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0vW0nnNKJfJieyH/TZ9UYAnTZs5/gHTdAe8=
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZVsCYMrIZBpFxwV26CbsuoEh5muXD5I1Ods=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/stereoscope v0.0.0-20200520221116-025e07f1c93e/go.mod h1:bkyLl5VITnrmgErv4S1vDfVz/TGAZ5il6161IQo7w2g=
|
||||
github.com/anchore/stereoscope v0.0.0-20200903223322-a3806f515470 h1:apXyPyfiaL/YQF7VeXRbDDB9TA7dA9rxdq8YbzPk9ko=
|
||||
github.com/anchore/stereoscope v0.0.0-20200903223322-a3806f515470/go.mod h1:WntReQTI/I27FOQ87UgLVVzWgku6+ZsqfOTLxpIZFCs=
|
||||
github.com/anchore/stereoscope v0.0.0-20200925184903-c82da54e98fe h1:m4NSyTo2fVUoUHAV/ZVqE/PFMr/y8oz9HRrhWLk9It0=
|
||||
github.com/anchore/stereoscope v0.0.0-20200925184903-c82da54e98fe/go.mod h1:2Jja/4l0zYggW52og+nn0rut4i+OYjCf9vTyrM8RT4E=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ=
|
||||
github.com/apex/log v1.3.0 h1:1fyfbPvUwD10nMoh3hY6MXzvZShJQn9/ck7ATgAt5pA=
|
||||
@@ -181,10 +180,11 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
|
||||
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
|
||||
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
|
||||
github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
|
||||
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
@@ -193,7 +193,6 @@ github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX
|
||||
github.com/containerd/containerd v1.3.4 h1:3o0smo5SKY7H6AJCmJhsnCjR2/V2T8VmiHt7seN2/kI=
|
||||
github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY=
|
||||
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe h1:PEmIrUvwG9Yyv+0WKZqjXfSFDeZjs/q15g0m08BYS9k=
|
||||
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo=
|
||||
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
|
||||
@@ -209,10 +208,12 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -321,7 +322,7 @@ github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b h1:ekuhfTjngPhisSjOJ0QWKpPQE8/rbknHaes6WVJj5Hw=
|
||||
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@@ -399,11 +400,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-containerregistry v0.0.0-20200430153450-5cbd060f5c92/go.mod h1:pD1UFYs7MCAx+ZLShBdttcaOSbyc8F9Na/9IZLNwJeA=
|
||||
github.com/google/go-containerregistry v0.1.0 h1:hL5mVw7cTX3SBr64Arpv+cJH93L+Z9Q6WjckImYLB3g=
|
||||
github.com/google/go-containerregistry v0.1.0/go.mod h1:npTSyywOeILcgWqd+rvtzGWflIPPcBQhYoOONaY4ltM=
|
||||
github.com/google/go-containerregistry v0.1.1 h1:AG8FSAfXglim2l5qSrqp5VK2Xl03PiBf25NiTGGamws=
|
||||
github.com/google/go-containerregistry v0.1.1/go.mod h1:npTSyywOeILcgWqd+rvtzGWflIPPcBQhYoOONaY4ltM=
|
||||
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
||||
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
@@ -444,9 +442,8 @@ github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1K
|
||||
github.com/gookit/color v1.2.7 h1:4qePMNWZhrmbfYJDix+J4V2l0iVW+6jQGjicELlN14E=
|
||||
github.com/gookit/color v1.2.7/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/goreleaser/goreleaser v0.136.0 h1:Z+7XPrfGK11s/Sp+a06sx2FzGuCjTBdxN2ubpGvQbjY=
|
||||
github.com/goreleaser/goreleaser v0.136.0/go.mod h1:wiKrPUeSNh6Wu8nUHxZydSOVQ/OZvOaO7DTtFqie904=
|
||||
github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w=
|
||||
@@ -474,18 +471,12 @@ 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-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU=
|
||||
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
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=
|
||||
@@ -506,8 +497,6 @@ 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=
|
||||
@@ -518,8 +507,6 @@ 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 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
||||
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=
|
||||
@@ -599,7 +586,6 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
@@ -622,8 +608,6 @@ 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=
|
||||
@@ -652,8 +636,6 @@ 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=
|
||||
@@ -682,7 +664,7 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM
|
||||
github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/package-url/packageurl-go v0.1.0 h1:efWBc98O/dBZRg1pw2xiDzovnlMjCa9NPnfaiBduh8I=
|
||||
github.com/package-url/packageurl-go v0.1.0/go.mod h1:C/ApiuWpmbpni4DIOECf6WCjFUZV7O1Fx7VAzrZHgBw=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
@@ -755,7 +737,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
@@ -781,6 +762,8 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/cobra v1.0.1-0.20200909172742-8a63648dd905 h1:Xn3y6St5vlEgvxekK6JuArarc79GKAj/jbcsMRCaRH4=
|
||||
github.com/spf13/cobra v1.0.1-0.20200909172742-8a63648dd905/go.mod h1:jCpPr/pv3OLY1D1nS9lN5HIdIpmOO/WTYJcAmnPq1nU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
@@ -803,6 +786,7 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
|
||||
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -835,8 +819,8 @@ github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbd
|
||||
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFODYDsg=
|
||||
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
|
||||
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/uudashr/gocognit v1.0.1 h1:MoG2fZ0b/Eo7NXoIwCVFLG5JED3qgQz5/NEE+rOsjPs=
|
||||
github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
@@ -938,7 +922,6 @@ 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=
|
||||
@@ -975,11 +958,10 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -996,8 +978,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1016,7 +996,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1028,8 +1007,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1037,6 +1015,7 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1045,14 +1024,11 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38=
|
||||
golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1115,7 +1091,6 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204192400-7124308813f3/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200210192313-1ace956b0e17/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
@@ -1165,7 +1140,6 @@ 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=
|
||||
@@ -1192,21 +1166,17 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200519141106-08726f379972/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece h1:1YM0uhfumvoDu9sx8+RyWwTI63zoCQvI23IYFRlvte0=
|
||||
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200604104852-0b0486081ffb h1:ek2py5bOqzR7MR/6obzk0rXUgYCLmjyLnaO9ssT+l6w=
|
||||
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=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
@@ -1214,8 +1184,6 @@ 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=
|
||||
@@ -1244,8 +1212,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y=
|
||||
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
|
||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
|
||||
@@ -28,13 +28,7 @@ type Application struct {
|
||||
Quiet bool `mapstructure:"quiet"`
|
||||
Log Logging `mapstructure:"log"`
|
||||
CliOptions CliOnlyOptions
|
||||
CheckForAppUpdate bool `mapstructure:"check-for-app-update"`
|
||||
Plugins Plugins `mapstructure:"plugins"`
|
||||
}
|
||||
|
||||
type Plugins struct {
|
||||
Enabled bool `mapstructure:"enabled"`
|
||||
Directory string `mapstructure:"dir"`
|
||||
CheckForAppUpdate bool `mapstructure:"check-for-app-update"`
|
||||
}
|
||||
|
||||
type Logging struct {
|
||||
|
||||
+1
-7
@@ -1,8 +1,6 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/logger"
|
||||
)
|
||||
import "github.com/anchore/syft/syft/logger"
|
||||
|
||||
var Log logger.Logger = &nopLogger{}
|
||||
|
||||
@@ -10,10 +8,6 @@ func Errorf(format string, args ...interface{}) {
|
||||
Log.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func Error(args ...interface{}) {
|
||||
Log.Error(args...)
|
||||
}
|
||||
|
||||
func Infof(format string, args ...interface{}) {
|
||||
Log.Infof(format, args...)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package log
|
||||
type nopLogger struct{}
|
||||
|
||||
func (l *nopLogger) Errorf(format string, args ...interface{}) {}
|
||||
func (l *nopLogger) Error(args ...interface{}) {}
|
||||
func (l *nopLogger) Infof(format string, args ...interface{}) {}
|
||||
func (l *nopLogger) Info(args ...interface{}) {}
|
||||
func (l *nopLogger) Debugf(format string, args ...interface{}) {}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
// Source: https://github.com/hashicorp/go-hclog/blob/master/stdlog.go (MIT License)
|
||||
|
||||
// Provides a io.Writer to shim the data out of *log.Logger
|
||||
// and back into our Logger. This is basically the only way to
|
||||
// build upon *log.Logger.
|
||||
type HCLogStdlogAdapter struct {
|
||||
log hclog.Logger
|
||||
inferLevels bool
|
||||
forceLevel hclog.Level
|
||||
}
|
||||
|
||||
// Take the data, infer the levels if configured, and send it through
|
||||
// a regular Logger.
|
||||
func (s *HCLogStdlogAdapter) Write(data []byte) (int, error) {
|
||||
str := string(bytes.TrimRight(data, " \t\n"))
|
||||
|
||||
if s.forceLevel != hclog.NoLevel {
|
||||
// Use pickLevel to strip log levels included in the line since we are
|
||||
// forcing the level
|
||||
_, str := s.pickLevel(str)
|
||||
|
||||
// Log at the forced level
|
||||
s.dispatch(str, s.forceLevel)
|
||||
} else if s.inferLevels {
|
||||
level, str := s.pickLevel(str)
|
||||
s.dispatch(str, level)
|
||||
} else {
|
||||
s.log.Info(str)
|
||||
}
|
||||
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
func (s *HCLogStdlogAdapter) dispatch(str string, level hclog.Level) {
|
||||
switch level {
|
||||
case hclog.Trace:
|
||||
s.log.Trace(str)
|
||||
case hclog.Debug:
|
||||
s.log.Debug(str)
|
||||
case hclog.Info:
|
||||
s.log.Info(str)
|
||||
case hclog.Warn:
|
||||
s.log.Warn(str)
|
||||
case hclog.Error:
|
||||
s.log.Error(str)
|
||||
default:
|
||||
s.log.Info(str)
|
||||
}
|
||||
}
|
||||
|
||||
// Detect, based on conventions, what log level this is.
|
||||
func (s *HCLogStdlogAdapter) pickLevel(str string) (hclog.Level, string) {
|
||||
switch {
|
||||
case strings.HasPrefix(str, "[DEBUG]"):
|
||||
return hclog.Debug, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[TRACE]"):
|
||||
return hclog.Trace, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[INFO]"):
|
||||
return hclog.Info, strings.TrimSpace(str[6:])
|
||||
case strings.HasPrefix(str, "[WARN]"):
|
||||
return hclog.Warn, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[ERROR]"):
|
||||
return hclog.Error, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[ERR]"):
|
||||
return hclog.Error, strings.TrimSpace(str[5:])
|
||||
default:
|
||||
return hclog.Info, str
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/anchore/syft/syft/logger"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ hclog.Logger = &LoggerHCLogAdapter{}
|
||||
|
||||
// LoggerHCLogAdapter is used to (partially) adapt a syft logger.Logger object to the hclog.Logger interface for syft plugins.
|
||||
// Note: this does not implement all functionality required by the hclog.Logger.
|
||||
type LoggerHCLogAdapter struct {
|
||||
Logger logger.Logger
|
||||
}
|
||||
|
||||
func NewLoggerHCLogAdapter(logger logger.Logger) *LoggerHCLogAdapter {
|
||||
return &LoggerHCLogAdapter{
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Args are alternating key, val pairs
|
||||
// keys must be strings
|
||||
// vals can be any type, but display is implementation specific
|
||||
// Emit a message and key/value pairs at a provided log level
|
||||
func (l *LoggerHCLogAdapter) Log(level hclog.Level, msg string, args ...interface{}) {
|
||||
l.Logger.Info(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the TRACE level
|
||||
func (l *LoggerHCLogAdapter) Trace(msg string, args ...interface{}) {
|
||||
l.Logger.Debug(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the DEBUG level
|
||||
func (l *LoggerHCLogAdapter) Debug(msg string, args ...interface{}) {
|
||||
l.Logger.Debug(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the INFO level
|
||||
func (l *LoggerHCLogAdapter) Info(msg string, args ...interface{}) {
|
||||
l.Logger.Info(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the WARN level
|
||||
func (l *LoggerHCLogAdapter) Warn(msg string, args ...interface{}) {
|
||||
l.Logger.Error(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the ERROR level
|
||||
func (l *LoggerHCLogAdapter) Error(msg string, args ...interface{}) {
|
||||
l.Logger.Error(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Indicate if TRACE logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsTrace() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// Indicate if DEBUG logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsDebug() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// Indicate if INFO logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsInfo() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// Indicate if WARN logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsWarn() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// Indicate if ERROR logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsError() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// ImpliedArgs returns With key/value pairs
|
||||
func (l *LoggerHCLogAdapter) ImpliedArgs() []interface{} {
|
||||
// TODO: not implemented
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates a sublogger that will always have the given key/value pairs
|
||||
func (l *LoggerHCLogAdapter) With(args ...interface{}) hclog.Logger {
|
||||
// TODO: not implemented
|
||||
return l
|
||||
}
|
||||
|
||||
// Returns the Name of the logger
|
||||
func (l *LoggerHCLogAdapter) Name() string {
|
||||
// TODO: not implemented
|
||||
return ""
|
||||
}
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// If the logger already has a name, the new value will be appended to the current
|
||||
// name. That way, a major subsystem can use this to decorate all it's own logs
|
||||
// without losing context.
|
||||
func (l *LoggerHCLogAdapter) Named(name string) hclog.Logger {
|
||||
// TODO: not implemented
|
||||
return l
|
||||
}
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// This sets the name of the logger to the value directly, unlike Named which honor
|
||||
// the current name as well.
|
||||
func (l *LoggerHCLogAdapter) ResetNamed(name string) hclog.Logger {
|
||||
// TODO: not implemented
|
||||
return l
|
||||
}
|
||||
|
||||
// Updates the level. This should affect all sub-loggers as well. If an
|
||||
// implementation cannot update the level on the fly, it should no-op.
|
||||
func (l *LoggerHCLogAdapter) SetLevel(level hclog.Level) {
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
||||
// Return a value that conforms to the stdlib log.Logger interface
|
||||
func (l *LoggerHCLogAdapter) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger {
|
||||
return log.New(l.StandardWriter(opts), "", log.LstdFlags)
|
||||
}
|
||||
|
||||
// Return a value that conforms to io.Writer, which can be passed into log.SetOutput()
|
||||
func (l *LoggerHCLogAdapter) StandardWriter(opts *hclog.StandardLoggerOptions) io.Writer {
|
||||
return &HCLogStdlogAdapter{
|
||||
log: l,
|
||||
inferLevels: opts.InferLevels,
|
||||
forceLevel: opts.ForceLevel,
|
||||
}
|
||||
}
|
||||
+13
-26
@@ -6,15 +6,10 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/syft/syft/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
prefixed "github.com/x-cray/logrus-prefixed-formatter"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ logger.Logger = &LogrusLogger{}
|
||||
var _ logger.Logger = &LogrusNestedLogger{}
|
||||
|
||||
type LogrusConfig struct {
|
||||
EnableConsole bool
|
||||
EnableFile bool
|
||||
@@ -81,50 +76,42 @@ func NewLogrusLogger(cfg LogrusConfig) *LogrusLogger {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Errorf(format string, args ...interface{}) {
|
||||
l.Logger.Errorf(format, args...)
|
||||
func (l *LogrusLogger) Debugf(format string, args ...interface{}) {
|
||||
l.Logger.Debugf(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Infof(format string, args ...interface{}) {
|
||||
l.Logger.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Debugf(format string, args ...interface{}) {
|
||||
l.Logger.Debugf(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Error(args ...interface{}) {
|
||||
l.Logger.Error(args...)
|
||||
func (l *LogrusLogger) Debug(args ...interface{}) {
|
||||
l.Logger.Debug(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Info(args ...interface{}) {
|
||||
l.Logger.Info(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Debug(args ...interface{}) {
|
||||
l.Logger.Debug(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Errorf(format string, args ...interface{}) {
|
||||
func (l *LogrusLogger) Errorf(format string, args ...interface{}) {
|
||||
l.Logger.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Infof(format string, args ...interface{}) {
|
||||
l.Logger.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Debugf(format string, args ...interface{}) {
|
||||
l.Logger.Debugf(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Error(args ...interface{}) {
|
||||
l.Logger.Error(args...)
|
||||
func (l *LogrusNestedLogger) Infof(format string, args ...interface{}) {
|
||||
l.Logger.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Debug(args ...interface{}) {
|
||||
l.Logger.Debug(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Info(args ...interface{}) {
|
||||
l.Logger.Info(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Debug(args ...interface{}) {
|
||||
l.Logger.Debug(args...)
|
||||
func (l *LogrusNestedLogger) Errorf(format string, args ...interface{}) {
|
||||
l.Logger.Errorf(format, args...)
|
||||
}
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ hclog.Logger = &LogrusHCLogAdapter{}
|
||||
|
||||
var levels = map[hclog.Level]logrus.Level{
|
||||
hclog.NoLevel: logrus.PanicLevel,
|
||||
hclog.Error: logrus.ErrorLevel,
|
||||
hclog.Warn: logrus.WarnLevel,
|
||||
hclog.Info: logrus.InfoLevel,
|
||||
hclog.Debug: logrus.DebugLevel,
|
||||
hclog.Trace: logrus.TraceLevel,
|
||||
}
|
||||
|
||||
// LogrusHCLogAdapter is used to adapt a logrus logger object to the hclog.Logger interface for syft plugins.
|
||||
type LogrusHCLogAdapter struct {
|
||||
logger *logrus.Logger
|
||||
entry *logrus.Entry
|
||||
}
|
||||
|
||||
func NewLogrusHCLogAdapter(logger *logrus.Logger, fields map[string]interface{}) *LogrusHCLogAdapter {
|
||||
if fields != nil {
|
||||
return &LogrusHCLogAdapter{
|
||||
logger: logger,
|
||||
entry: logger.WithFields(fields),
|
||||
}
|
||||
}
|
||||
return &LogrusHCLogAdapter{
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LogrusHCLogAdapter) log(level hclog.Level, msg string, args ...interface{}) {
|
||||
if l.entry != nil {
|
||||
l.entry.WithFields(makeArgFields(args...)).Log(levels[level], msg)
|
||||
return
|
||||
}
|
||||
l.logger.WithFields(makeArgFields(args...)).Log(levels[level], msg)
|
||||
}
|
||||
|
||||
// Args are alternating key, val pairs
|
||||
// keys must be strings
|
||||
// vals can be any type, but display is implementation specific
|
||||
// Emit a message and key/value pairs at a provided log level
|
||||
func (l *LogrusHCLogAdapter) Log(level hclog.Level, msg string, args ...interface{}) {
|
||||
l.log(level, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the TRACE level
|
||||
func (l *LogrusHCLogAdapter) Trace(msg string, args ...interface{}) {
|
||||
l.log(hclog.Trace, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the DEBUG level
|
||||
func (l *LogrusHCLogAdapter) Debug(msg string, args ...interface{}) {
|
||||
l.log(hclog.Debug, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the INFO level
|
||||
func (l *LogrusHCLogAdapter) Info(msg string, args ...interface{}) {
|
||||
l.log(hclog.Info, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the WARN level
|
||||
func (l *LogrusHCLogAdapter) Warn(msg string, args ...interface{}) {
|
||||
l.log(hclog.Warn, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the ERROR level
|
||||
func (l *LogrusHCLogAdapter) Error(msg string, args ...interface{}) {
|
||||
l.log(hclog.Error, msg, args...)
|
||||
}
|
||||
|
||||
// Indicate if TRACE logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsTrace() bool {
|
||||
return l.logger.Level <= logrus.TraceLevel
|
||||
}
|
||||
|
||||
// Indicate if DEBUG logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsDebug() bool {
|
||||
return l.logger.Level <= logrus.DebugLevel
|
||||
}
|
||||
|
||||
// Indicate if INFO logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsInfo() bool {
|
||||
return l.logger.Level <= logrus.InfoLevel
|
||||
}
|
||||
|
||||
// Indicate if WARN logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsWarn() bool {
|
||||
return l.logger.Level <= logrus.WarnLevel
|
||||
}
|
||||
|
||||
// Indicate if ERROR logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsError() bool {
|
||||
return l.logger.Level <= logrus.ErrorLevel
|
||||
}
|
||||
|
||||
// ImpliedArgs returns With key/value pairs
|
||||
func (l *LogrusHCLogAdapter) ImpliedArgs() []interface{} {
|
||||
// TODO: not implemented
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates a sublogger that will always have the given key/value pairs
|
||||
func (l *LogrusHCLogAdapter) With(args ...interface{}) hclog.Logger {
|
||||
l.entry = l.logger.WithFields(makeArgFields(args...))
|
||||
return l
|
||||
}
|
||||
|
||||
// Returns the Name of the logger
|
||||
func (l *LogrusHCLogAdapter) Name() string {
|
||||
// TODO: not implemented
|
||||
return ""
|
||||
}
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// If the logger already has a name, the new value will be appended to the current
|
||||
// name. That way, a major subsystem can use this to decorate all it's own logs
|
||||
// without losing context.
|
||||
func (l *LogrusHCLogAdapter) Named(name string) hclog.Logger {
|
||||
return NewLogrusHCLogAdapter(l.logger, logrus.Fields{"name": name})
|
||||
}
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// This sets the name of the logger to the value directly, unlike Named which honor
|
||||
// the current name as well.
|
||||
func (l *LogrusHCLogAdapter) ResetNamed(name string) hclog.Logger {
|
||||
return NewLogrusHCLogAdapter(l.logger, logrus.Fields{"name": name})
|
||||
}
|
||||
|
||||
// Updates the level. This should affect all sub-loggers as well. If an
|
||||
// implementation cannot update the level on the fly, it should no-op.
|
||||
func (l *LogrusHCLogAdapter) SetLevel(level hclog.Level) {
|
||||
l.logger.SetLevel(levels[level])
|
||||
}
|
||||
|
||||
// Return a value that conforms to the stdlib log.Logger interface
|
||||
func (l *LogrusHCLogAdapter) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger {
|
||||
return log.New(l.StandardWriter(opts), "", log.LstdFlags)
|
||||
}
|
||||
|
||||
// Return a value that conforms to io.Writer, which can be passed into log.SetOutput()
|
||||
func (l *LogrusHCLogAdapter) StandardWriter(opts *hclog.StandardLoggerOptions) io.Writer {
|
||||
return &HCLogStdlogAdapter{
|
||||
log: l,
|
||||
inferLevels: opts.InferLevels,
|
||||
forceLevel: opts.ForceLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func makeArgFields(args ...interface{}) logrus.Fields {
|
||||
if len(args)%2 != 0 {
|
||||
panic(fmt.Errorf("odd number of logger key-value pairs (%d): %+v", len(args), args))
|
||||
}
|
||||
|
||||
var key string
|
||||
var fields = make(logrus.Fields)
|
||||
for i, arg := range args {
|
||||
if i%2 == 0 {
|
||||
key = arg.(string)
|
||||
} else {
|
||||
fields[key] = arg
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
@@ -16,13 +16,13 @@ var platform = fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
// Version defines the application version details (generally from build information)
|
||||
type Version struct {
|
||||
Version string // application semantic version
|
||||
GitCommit string // git SHA at build-time
|
||||
GitTreeState string // indication of git tree (either "clean" or "dirty") at build-time
|
||||
BuildDate string // date of the build
|
||||
GoVersion string // go runtime version at build-time
|
||||
Compiler string // compiler used at build-time
|
||||
Platform string // GOOS and GOARCH at build-time
|
||||
Version string `json:"version"` // application semantic version
|
||||
GitCommit string `json:"gitCommit"` // git SHA at build-time
|
||||
GitTreeState string `json:"gitTreeState"` // indication of git tree (either "clean" or "dirty") at build-time
|
||||
BuildDate string `json:"buildDate"` // date of the build
|
||||
GoVersion string `json:"goVersion"` // go runtime version at build-time
|
||||
Compiler string `json:"compiler"` // compiler used at build-time
|
||||
Platform string `json:"platform"` // GOOS and GOARCH at build-time
|
||||
}
|
||||
|
||||
// FromBuild provides all version details
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Source this file in your shell sessions in order to use this shell completion.
|
||||
|
||||
complete -W "$(docker images --format '{{.Repository}}:{{.Tag}}')" syft
|
||||
+134
-108
@@ -4,7 +4,7 @@
|
||||
"artifacts": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"found-by": {
|
||||
"foundBy": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -18,7 +18,7 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"layer-index": {
|
||||
"layerIndex": {
|
||||
"type": "integer"
|
||||
},
|
||||
"path": {
|
||||
@@ -26,7 +26,7 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"layer-index",
|
||||
"layerIndex",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
@@ -52,10 +52,10 @@
|
||||
"checksum": {
|
||||
"type": "string"
|
||||
},
|
||||
"owner-gid": {
|
||||
"ownerGid": {
|
||||
"type": "string"
|
||||
},
|
||||
"owner-uid": {
|
||||
"ownerUid": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
@@ -67,8 +67,8 @@
|
||||
},
|
||||
"required": [
|
||||
"checksum",
|
||||
"owner-gid",
|
||||
"owner-uid",
|
||||
"ownerGid",
|
||||
"ownerUid",
|
||||
"path",
|
||||
"permissions"
|
||||
],
|
||||
@@ -76,10 +76,10 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"git-commit-of-apk-port": {
|
||||
"gitCommitOfApkPort": {
|
||||
"type": "string"
|
||||
},
|
||||
"installed-size": {
|
||||
"installedSize": {
|
||||
"type": "integer"
|
||||
},
|
||||
"license": {
|
||||
@@ -95,7 +95,7 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"extra-fields": {
|
||||
"extraFields": {
|
||||
"properties": {
|
||||
"Archiver-Version": {
|
||||
"type": "string"
|
||||
@@ -160,60 +160,63 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"implementation-title": {
|
||||
"implementationTitle": {
|
||||
"type": "string"
|
||||
},
|
||||
"implementation-vendor": {
|
||||
"implementationVendor": {
|
||||
"type": "string"
|
||||
},
|
||||
"implementation-version": {
|
||||
"implementationVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"manifest-version": {
|
||||
"manifestVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"specification-title": {
|
||||
"specificationTitle": {
|
||||
"type": "string"
|
||||
},
|
||||
"specification-vendor": {
|
||||
"specificationVendor": {
|
||||
"type": "string"
|
||||
},
|
||||
"specification-version": {
|
||||
"specificationVersion": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"extra-fields",
|
||||
"implementation-title",
|
||||
"implementation-vendor",
|
||||
"implementation-version",
|
||||
"manifest-version",
|
||||
"extraFields",
|
||||
"implementationTitle",
|
||||
"implementationVendor",
|
||||
"implementationVersion",
|
||||
"manifestVersion",
|
||||
"name",
|
||||
"specification-title",
|
||||
"specification-vendor",
|
||||
"specification-version"
|
||||
"specificationTitle",
|
||||
"specificationVendor",
|
||||
"specificationVersion"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"origin-package": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"originPackage": {
|
||||
"type": "string"
|
||||
},
|
||||
"package": {
|
||||
"type": "string"
|
||||
},
|
||||
"parent-package": {
|
||||
"parentPackage": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "null"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"found-by": {
|
||||
"foundBy": {
|
||||
"type": "string"
|
||||
},
|
||||
"language": {
|
||||
@@ -229,7 +232,7 @@
|
||||
"properties": {
|
||||
"manifest": {
|
||||
"properties": {
|
||||
"extra-fields": {
|
||||
"extraFields": {
|
||||
"properties": {
|
||||
"Archiver-Version": {
|
||||
"type": "string"
|
||||
@@ -294,59 +297,59 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"implementation-title": {
|
||||
"implementationTitle": {
|
||||
"type": "string"
|
||||
},
|
||||
"implementation-vendor": {
|
||||
"implementationVendor": {
|
||||
"type": "string"
|
||||
},
|
||||
"implementation-version": {
|
||||
"implementationVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"manifest-version": {
|
||||
"manifestVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"specification-title": {
|
||||
"specificationTitle": {
|
||||
"type": "string"
|
||||
},
|
||||
"specification-vendor": {
|
||||
"specificationVendor": {
|
||||
"type": "string"
|
||||
},
|
||||
"specification-version": {
|
||||
"specificationVersion": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"extra-fields",
|
||||
"implementation-title",
|
||||
"implementation-vendor",
|
||||
"implementation-version",
|
||||
"manifest-version",
|
||||
"extraFields",
|
||||
"implementationTitle",
|
||||
"implementationVendor",
|
||||
"implementationVersion",
|
||||
"manifestVersion",
|
||||
"name",
|
||||
"specification-title",
|
||||
"specification-vendor",
|
||||
"specification-version"
|
||||
"specificationTitle",
|
||||
"specificationVendor",
|
||||
"specificationVersion"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"parent-package": {
|
||||
"parentPackage": {
|
||||
"type": "null"
|
||||
},
|
||||
"pom-properties": {
|
||||
"pomProperties": {
|
||||
"properties": {
|
||||
"Path": {
|
||||
"type": "string"
|
||||
},
|
||||
"artifact-id": {
|
||||
"artifactId": {
|
||||
"type": "string"
|
||||
},
|
||||
"extra-fields": {
|
||||
"extraFields": {
|
||||
"type": "null"
|
||||
},
|
||||
"group-id": {
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
@@ -358,9 +361,9 @@
|
||||
},
|
||||
"required": [
|
||||
"Path",
|
||||
"artifact-id",
|
||||
"extra-fields",
|
||||
"group-id",
|
||||
"artifactId",
|
||||
"extraFields",
|
||||
"groupId",
|
||||
"name",
|
||||
"version"
|
||||
],
|
||||
@@ -369,8 +372,8 @@
|
||||
},
|
||||
"required": [
|
||||
"manifest",
|
||||
"parent-package",
|
||||
"pom-properties"
|
||||
"parentPackage",
|
||||
"pomProperties"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
@@ -385,7 +388,7 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"found-by",
|
||||
"foundBy",
|
||||
"language",
|
||||
"licenses",
|
||||
"manifest",
|
||||
@@ -398,18 +401,18 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"pom-properties": {
|
||||
"pomProperties": {
|
||||
"properties": {
|
||||
"Path": {
|
||||
"type": "string"
|
||||
},
|
||||
"artifact-id": {
|
||||
"artifactId": {
|
||||
"type": "string"
|
||||
},
|
||||
"extra-fields": {
|
||||
"extraFields": {
|
||||
"type": "null"
|
||||
},
|
||||
"group-id": {
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
@@ -421,18 +424,18 @@
|
||||
},
|
||||
"required": [
|
||||
"Path",
|
||||
"artifact-id",
|
||||
"extra-fields",
|
||||
"group-id",
|
||||
"artifactId",
|
||||
"extraFields",
|
||||
"groupId",
|
||||
"name",
|
||||
"version"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"pull-checksum": {
|
||||
"pullChecksum": {
|
||||
"type": "string"
|
||||
},
|
||||
"pull-dependencies": {
|
||||
"pullDependencies": {
|
||||
"type": "string"
|
||||
},
|
||||
"release": {
|
||||
@@ -444,9 +447,15 @@
|
||||
"source": {
|
||||
"type": "string"
|
||||
},
|
||||
"sourceRpm": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -464,7 +473,7 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"found-by",
|
||||
"foundBy",
|
||||
"locations",
|
||||
"name",
|
||||
"type",
|
||||
@@ -474,61 +483,78 @@
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string"
|
||||
},
|
||||
"image": {
|
||||
"source": {
|
||||
"properties": {
|
||||
"digest": {
|
||||
"type": "string"
|
||||
},
|
||||
"layers": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"digest": {
|
||||
"type": "string"
|
||||
},
|
||||
"media-type": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
}
|
||||
"target": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
"required": [
|
||||
"digest",
|
||||
"media-type",
|
||||
"size"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
{
|
||||
"properties": {
|
||||
"digest": {
|
||||
"type": "string"
|
||||
},
|
||||
"layers": {
|
||||
"items": {
|
||||
"properties": {
|
||||
"digest": {
|
||||
"type": "string"
|
||||
},
|
||||
"mediaType": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"digest",
|
||||
"mediaType",
|
||||
"size"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"mediaType": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tags": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"digest",
|
||||
"layers",
|
||||
"mediaType",
|
||||
"size",
|
||||
"tags"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"media-type": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"tags": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"digest",
|
||||
"layers",
|
||||
"media-type",
|
||||
"size",
|
||||
"tags"
|
||||
"target",
|
||||
"type"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"artifacts"
|
||||
"artifacts",
|
||||
"source"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
@@ -4,8 +4,6 @@ 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"
|
||||
@@ -29,16 +27,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (c *Cataloger) Name() string {
|
||||
func (a *Cataloger) Name() string {
|
||||
return "apkdb-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Alpine DB files from the user content source.
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Alpine DB files discovered.
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ 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"
|
||||
@@ -29,16 +27,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (c *Cataloger) Name() string {
|
||||
func (a *Cataloger) Name() string {
|
||||
return "bundler-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Gemfile.lock files from the user content source.
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Gemfile.lock files discovered.
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
}
|
||||
|
||||
+52
-55
@@ -12,61 +12,6 @@ import (
|
||||
"github.com/wagoodman/go-progress"
|
||||
)
|
||||
|
||||
// Catalog a given scope (container image or filesystem) with the given catalogers, returning all discovered packages.
|
||||
// In order to efficiently retrieve contents from a underlying container image the content fetch requests are
|
||||
// done in bulk. Specifically, all files of interest are collected from each catalogers and accumulated into a single
|
||||
// request.
|
||||
func Catalog(resolver scope.Resolver, catalogers ...Cataloger) (*pkg.Catalog, error) {
|
||||
catalog := pkg.NewCatalog()
|
||||
fileSelection := make([]file.Reference, 0)
|
||||
|
||||
filesProcessed, packagesDiscovered := newMonitor()
|
||||
|
||||
// ask catalogers for files to extract from the image tar
|
||||
for _, a := range catalogers {
|
||||
catalogerSelection := a.SelectFiles(resolver)
|
||||
fileSelection = append(fileSelection, catalogerSelection...)
|
||||
log.Debugf("cataloger '%s' selected '%d' files", a.Name(), len(catalogerSelection))
|
||||
filesProcessed.N += int64(len(fileSelection))
|
||||
}
|
||||
|
||||
// fetch contents for requested selection by catalogers
|
||||
// TODO: we should consider refactoring to return a set of io.Readers instead of the full contents themselves (allow for optional buffering).
|
||||
contents, err := resolver.MultipleFileContentsByRef(fileSelection...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// perform analysis, accumulating errors for each failed analysis
|
||||
var errs error
|
||||
for _, c := range catalogers {
|
||||
// TODO: check for multiple rounds of analyses by Iterate error
|
||||
packages, err := c.Catalog(contents)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("cataloger '%s' discovered '%d' packages", c.Name(), len(packages))
|
||||
packagesDiscovered.N += int64(len(packages))
|
||||
|
||||
catalogerName := c.Name()
|
||||
for _, p := range packages {
|
||||
p.FoundBy = catalogerName
|
||||
catalog.Add(p)
|
||||
}
|
||||
}
|
||||
|
||||
if errs != nil {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
filesProcessed.SetCompleted()
|
||||
packagesDiscovered.SetCompleted()
|
||||
|
||||
return catalog, nil
|
||||
}
|
||||
|
||||
// Monitor provides progress-related data for observing the progress of a Catalog() call (published on the event bus).
|
||||
type Monitor struct {
|
||||
FilesProcessed progress.Monitorable // the number of files selected and contents analyzed from all registered catalogers
|
||||
@@ -87,3 +32,55 @@ func newMonitor() (*progress.Manual, *progress.Manual) {
|
||||
})
|
||||
return &filesProcessed, &packagesDiscovered
|
||||
}
|
||||
|
||||
// Catalog a given scope (container image or filesystem) with the given catalogers, returning all discovered packages.
|
||||
// In order to efficiently retrieve contents from a underlying container image the content fetch requests are
|
||||
// done in bulk. Specifically, all files of interest are collected from each catalogers and accumulated into a single
|
||||
// request.
|
||||
func Catalog(resolver scope.Resolver, catalogers ...Cataloger) (*pkg.Catalog, error) {
|
||||
catalog := pkg.NewCatalog()
|
||||
fileSelection := make([]file.Reference, 0)
|
||||
|
||||
filesProcessed, packagesDiscovered := newMonitor()
|
||||
|
||||
// ask catalogers for files to extract from the image tar
|
||||
for _, a := range catalogers {
|
||||
fileSelection = append(fileSelection, a.SelectFiles(resolver)...)
|
||||
log.Debugf("cataloger '%s' selected '%d' files", a.Name(), len(fileSelection))
|
||||
filesProcessed.N += int64(len(fileSelection))
|
||||
}
|
||||
|
||||
// fetch contents for requested selection by catalogers
|
||||
// TODO: we should consider refactoring to return a set of io.Readers instead of the full contents themselves (allow for optional buffering).
|
||||
contents, err := resolver.MultipleFileContentsByRef(fileSelection...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// perform analysis, accumulating errors for each failed analysis
|
||||
var errs error
|
||||
for _, a := range catalogers {
|
||||
// TODO: check for multiple rounds of analyses by Iterate error
|
||||
packages, err := a.Catalog(contents)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("cataloger '%s' discovered '%d' packages", a.Name(), len(packages))
|
||||
packagesDiscovered.N += int64(len(packages))
|
||||
|
||||
for _, p := range packages {
|
||||
catalog.Add(p)
|
||||
}
|
||||
}
|
||||
|
||||
if errs != nil {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
filesProcessed.SetCompleted()
|
||||
packagesDiscovered.SetCompleted()
|
||||
|
||||
return catalog, nil
|
||||
}
|
||||
|
||||
@@ -6,13 +6,10 @@ catalogers defined in child packages as well as the interface definition to impl
|
||||
package cataloger
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/syft/syft/cataloger/dpkg"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/apkdb"
|
||||
"github.com/anchore/syft/syft/cataloger/bundler"
|
||||
"github.com/anchore/syft/syft/cataloger/dpkg"
|
||||
"github.com/anchore/syft/syft/cataloger/golang"
|
||||
"github.com/anchore/syft/syft/cataloger/java"
|
||||
"github.com/anchore/syft/syft/cataloger/javascript"
|
||||
@@ -31,12 +28,13 @@ type Cataloger interface {
|
||||
// SelectFiles discovers and returns specific files that the cataloger would like to inspect the contents of.
|
||||
SelectFiles(scope.FileResolver) []file.Reference
|
||||
// Catalog is given the file contents and should return any discovered Packages after analyzing the contents.
|
||||
Catalog(map[file.Reference]io.Reader) ([]pkg.Package, error)
|
||||
Catalog(map[file.Reference]string) ([]pkg.Package, error)
|
||||
// TODO: add "IterationNeeded" error to indicate to the driver to continue with another Select/Catalog pass
|
||||
// TODO: we should consider refactoring to return a set of io.Readers instead of the full contents themselves (allow for optional buffering).
|
||||
}
|
||||
|
||||
// All returns a slice of all locally defined catalogers (defined in child packages).
|
||||
func BuiltIn() []Cataloger {
|
||||
func All() []Cataloger {
|
||||
return []Cataloger{
|
||||
dpkg.New(),
|
||||
bundler.New(),
|
||||
|
||||
@@ -4,7 +4,7 @@ Package common provides generic utilities used by multiple catalogers.
|
||||
package common
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
@@ -73,7 +73,7 @@ func (a *GenericCataloger) SelectFiles(resolver scope.FileResolver) []file.Refer
|
||||
}
|
||||
|
||||
// Catalog takes a set of file contents and uses any configured parser functions to resolve and return discovered packages
|
||||
func (a *GenericCataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
func (a *GenericCataloger) Catalog(contents map[file.Reference]string, upstreamMatcher string) ([]pkg.Package, error) {
|
||||
defer a.clear()
|
||||
|
||||
packages := make([]pkg.Package, 0)
|
||||
@@ -81,18 +81,19 @@ func (a *GenericCataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg
|
||||
for reference, parser := range a.parsers {
|
||||
content, ok := contents[reference]
|
||||
if !ok {
|
||||
log.Errorf("cataloger missing file content: %+v", reference)
|
||||
log.Errorf("cataloger '%s' missing file content: %+v", upstreamMatcher, reference)
|
||||
continue
|
||||
}
|
||||
|
||||
entries, err := parser(string(reference.Path), content)
|
||||
entries, err := parser(string(reference.Path), strings.NewReader(content))
|
||||
if err != nil {
|
||||
// TODO: should we fail? or only log?
|
||||
log.Errorf("cataloger failed to parse entries (reference=%+v): %w", reference, err)
|
||||
log.Errorf("cataloger '%s' failed to parse entries (reference=%+v): %w", upstreamMatcher, reference, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
entry.FoundBy = upstreamMatcher
|
||||
entry.Source = []file.Reference{reference}
|
||||
|
||||
packages = append(packages, entry)
|
||||
|
||||
@@ -79,15 +79,17 @@ func TestGenericCataloger(t *testing.T) {
|
||||
selectionByPath[string(s.Path)] = s
|
||||
}
|
||||
|
||||
upstream := "some-other-cataloger"
|
||||
expectedPkgs := make(map[file.Reference]pkg.Package)
|
||||
for path, ref := range selectionByPath {
|
||||
expectedPkgs[ref] = pkg.Package{
|
||||
Source: []file.Reference{ref},
|
||||
Name: fmt.Sprintf("%s file contents!", path),
|
||||
FoundBy: upstream,
|
||||
Source: []file.Reference{ref},
|
||||
Name: fmt.Sprintf("%s file contents!", path),
|
||||
}
|
||||
}
|
||||
|
||||
actualPkgs, err := cataloger.Catalog(resolver.contents)
|
||||
actualPkgs, err := cataloger.Catalog(resolver.contents, upstream)
|
||||
if err != nil {
|
||||
t.Fatalf("cataloger catalog action failed: %+v", err)
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ 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"
|
||||
@@ -29,16 +27,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (c *Cataloger) Name() string {
|
||||
func (a *Cataloger) Name() string {
|
||||
return "dpkg-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered DPKG status files from the user content source.
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all DPKG status files discovered.
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ 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"
|
||||
@@ -29,16 +27,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (c *Cataloger) Name() string {
|
||||
func (a *Cataloger) Name() string {
|
||||
return "go-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered go.mod files from the user content source.
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all go.mod files discovered.
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ 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"
|
||||
@@ -30,16 +28,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (c *Cataloger) Name() string {
|
||||
func (a *Cataloger) Name() string {
|
||||
return "java-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Java archive files from the user content source.
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Java archive files discovered.
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ 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"
|
||||
@@ -30,16 +28,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (c *Cataloger) Name() string {
|
||||
func (a *Cataloger) Name() string {
|
||||
return "javascript-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Javascript ecosystem files from the user content source.
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Javascript ecosystem files discovered.
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ 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"
|
||||
@@ -22,7 +20,7 @@ func New() *Cataloger {
|
||||
globParsers := map[string]common.ParserFn{
|
||||
"**/*egg-info/PKG-INFO": parseEggMetadata,
|
||||
"**/*dist-info/METADATA": parseWheelMetadata,
|
||||
"**/requirements.txt": parseRequirementsTxt,
|
||||
"**/*requirements*.txt": parseRequirementsTxt,
|
||||
"**/poetry.lock": parsePoetryLock,
|
||||
"**/setup.py": parseSetup,
|
||||
}
|
||||
@@ -33,16 +31,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (c *Cataloger) Name() string {
|
||||
func (a *Cataloger) Name() string {
|
||||
return "python-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Python ecosystem files from the user content source.
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Python ecosystem files discovered.
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ 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"
|
||||
@@ -29,16 +27,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (c *Cataloger) Name() string {
|
||||
func (a *Cataloger) Name() string {
|
||||
return "rpmdb-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered RPM DB files from the user content source.
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all RPM DB files discovered.
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
}
|
||||
|
||||
+11
-1
@@ -20,6 +20,9 @@ func NewUnknownDistro() Distro {
|
||||
}
|
||||
|
||||
func NewDistro(t Type, ver string) (Distro, error) {
|
||||
if ver == "" {
|
||||
return Distro{Type: t}, nil
|
||||
}
|
||||
verObj, err := hashiVer.NewVersion(ver)
|
||||
if err != nil {
|
||||
return Distro{}, fmt.Errorf("could not create distro version: %w", err)
|
||||
@@ -32,6 +35,9 @@ func NewDistro(t Type, ver string) (Distro, error) {
|
||||
}
|
||||
|
||||
func (d Distro) MajorVersion() string {
|
||||
if d.Version == nil {
|
||||
return fmt.Sprint("(version unknown)")
|
||||
}
|
||||
return fmt.Sprintf("%d", d.Version.Segments()[0])
|
||||
}
|
||||
|
||||
@@ -40,7 +46,11 @@ func (d Distro) FullVersion() string {
|
||||
}
|
||||
|
||||
func (d Distro) String() string {
|
||||
return fmt.Sprintf("%s %s", d.Type, d.RawVersion)
|
||||
versionStr := "(version unknown)"
|
||||
if d.RawVersion != "" {
|
||||
versionStr = d.RawVersion
|
||||
}
|
||||
return fmt.Sprintf("%s %s", d.Type, versionStr)
|
||||
}
|
||||
|
||||
// Name provides a string repr of the distro
|
||||
|
||||
+4
-14
@@ -1,7 +1,6 @@
|
||||
package distro
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@@ -11,7 +10,6 @@ import (
|
||||
)
|
||||
|
||||
// returns a distro or nil
|
||||
// TODO: refactor to io.Reader
|
||||
type parseFunc func(string) *Distro
|
||||
|
||||
type parseEntry struct {
|
||||
@@ -19,7 +17,6 @@ type parseEntry struct {
|
||||
fn parseFunc
|
||||
}
|
||||
|
||||
// nolint: funlen
|
||||
// Identify parses distro-specific files to determine distro metadata like version and release.
|
||||
func Identify(resolver scope.Resolver) Distro {
|
||||
distro := NewUnknownDistro()
|
||||
@@ -51,12 +48,13 @@ identifyLoop:
|
||||
}
|
||||
|
||||
if len(refs) == 0 {
|
||||
log.Debugf("No Refs found from path: %s", entry.path)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ref := range refs {
|
||||
contentReaders, err := resolver.MultipleFileContentsByRef(ref)
|
||||
contentReader, ok := contentReaders[ref]
|
||||
contents, err := resolver.MultipleFileContentsByRef(ref)
|
||||
content, ok := contents[ref]
|
||||
|
||||
if !ok {
|
||||
log.Infof("no content present for ref: %s", ref)
|
||||
@@ -68,14 +66,6 @@ identifyLoop:
|
||||
continue
|
||||
}
|
||||
|
||||
bytes, err := ioutil.ReadAll(contentReader)
|
||||
if err != nil {
|
||||
log.Debugf("unable to read contents from %s: %s", entry.path, err)
|
||||
continue
|
||||
}
|
||||
|
||||
content := string(bytes)
|
||||
|
||||
if content == "" {
|
||||
log.Debugf("no contents in file, skipping: %s", entry.path)
|
||||
continue
|
||||
@@ -95,7 +85,7 @@ func assemble(name, version string) *Distro {
|
||||
distroType, ok := IDMapping[name]
|
||||
|
||||
// Both distro and version must be present
|
||||
if len(name) == 0 || len(version) == 0 {
|
||||
if len(name) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,15 @@ func TestIdentifyDistro(t *testing.T) {
|
||||
fixture: "test-fixtures/os/unmatchable",
|
||||
Type: UnknownDistroType,
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/os/opensuse-leap",
|
||||
Type: OpenSuseLeap,
|
||||
Version: "15.2.0",
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/os/arch",
|
||||
Type: ArchLinux,
|
||||
},
|
||||
}
|
||||
|
||||
observedDistros := internal.NewStringSet()
|
||||
@@ -94,6 +103,11 @@ func TestIdentifyDistro(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
if d.Version == nil {
|
||||
t.Log("Distro doesn't have a Version")
|
||||
return
|
||||
}
|
||||
|
||||
if d.Version.String() != test.Version {
|
||||
t.Errorf("expected distro version doesn't match: %v != %v", d.Version.String(), test.Version)
|
||||
}
|
||||
@@ -175,10 +189,6 @@ func TestParseOsReleaseFailures(t *testing.T) {
|
||||
fixture string
|
||||
name string
|
||||
}{
|
||||
{
|
||||
fixture: "test-fixtures/bad-version",
|
||||
name: "No version",
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/bad-id",
|
||||
name: "No name ID",
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
NAME="Red Hat Enterprise Linux"
|
||||
VERSION="8.1 (Ootpa)"
|
||||
ID="rhel"
|
||||
ID_LIKE="fedora"
|
||||
PLATFORM_ID="platform:el8"
|
||||
PRETTY_NAME="Red Hat Enterprise Linux 8.1 (Ootpa)"
|
||||
ANSI_COLOR="0;31"
|
||||
CPE_NAME="cpe:/o:redhat:enterprise_linux:8.1:GA"
|
||||
HOME_URL="https://www.redhat.com/"
|
||||
BUG_REPORT_URL="https://bugzilla.redhat.com/"
|
||||
|
||||
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
|
||||
REDHAT_BUGZILLA_PRODUCT_VERSION=8.1
|
||||
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
|
||||
REDHAT_SUPPORT_PRODUCT_VERSION="8.1"
|
||||
@@ -0,0 +1,10 @@
|
||||
NAME="Arch Linux"
|
||||
PRETTY_NAME="Arch Linux"
|
||||
ID=arch
|
||||
BUILD_ID=rolling
|
||||
ANSI_COLOR="38;2;23;147;209"
|
||||
HOME_URL="https://www.archlinux.org/"
|
||||
DOCUMENTATION_URL="https://wiki.archlinux.org/"
|
||||
SUPPORT_URL="https://bbs.archlinux.org/"
|
||||
BUG_REPORT_URL="https://bugs.archlinux.org/"
|
||||
LOGO=archlinux
|
||||
@@ -0,0 +1,10 @@
|
||||
NAME="openSUSE Leap"
|
||||
VERSION="15.2"
|
||||
ID="opensuse-leap"
|
||||
ID_LIKE="suse opensuse"
|
||||
VERSION_ID="15.2"
|
||||
PRETTY_NAME="openSUSE Leap 15.2"
|
||||
ANSI_COLOR="0;32"
|
||||
CPE_NAME="cpe:/o:opensuse:leap:15.2"
|
||||
BUG_REPORT_URL="https://bugs.opensuse.org"
|
||||
HOME_URL="https://www.opensuse.org/"
|
||||
+17
-13
@@ -11,7 +11,8 @@ const (
|
||||
Busybox
|
||||
AmazonLinux
|
||||
OracleLinux
|
||||
//ArchLinux
|
||||
ArchLinux
|
||||
OpenSuseLeap
|
||||
)
|
||||
|
||||
type Type int
|
||||
@@ -27,7 +28,8 @@ var distroStr = []string{
|
||||
"busybox",
|
||||
"amazn",
|
||||
"oraclelinux",
|
||||
//"archlinux",
|
||||
"archlinux",
|
||||
"opensuse-leap",
|
||||
}
|
||||
|
||||
var All = []Type{
|
||||
@@ -40,7 +42,8 @@ var All = []Type{
|
||||
Busybox,
|
||||
AmazonLinux,
|
||||
OracleLinux,
|
||||
//ArchLinux,
|
||||
ArchLinux,
|
||||
OpenSuseLeap,
|
||||
}
|
||||
|
||||
func (t Type) String() string {
|
||||
@@ -53,14 +56,15 @@ func (t Type) String() string {
|
||||
|
||||
// IDMapping connects a distro ID like "ubuntu" to a Distro type
|
||||
var IDMapping = map[string]Type{
|
||||
"debian": Debian,
|
||||
"ubuntu": Ubuntu,
|
||||
"rhel": RedHat,
|
||||
"centos": CentOS,
|
||||
"fedora": Fedora,
|
||||
"alpine": Alpine,
|
||||
"busybox": Busybox,
|
||||
"amzn": AmazonLinux,
|
||||
"ol": OracleLinux,
|
||||
//"arch": ArchLinux,
|
||||
"debian": Debian,
|
||||
"ubuntu": Ubuntu,
|
||||
"rhel": RedHat,
|
||||
"centos": CentOS,
|
||||
"fedora": Fedora,
|
||||
"alpine": Alpine,
|
||||
"busybox": Busybox,
|
||||
"amzn": AmazonLinux,
|
||||
"ol": OracleLinux,
|
||||
"arch": ArchLinux,
|
||||
"opensuse-leap": OpenSuseLeap,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
/*
|
||||
A "one-stop-shop" for helper utilities for all major functionality provided by child packages of the syft library.
|
||||
|
||||
Here is what the main execution path for syft does:
|
||||
|
||||
1. Parse a user image string to get a stereoscope image.Source object
|
||||
2. Invoke all catalogers to catalog the image, adding discovered packages to a single catalog object
|
||||
3. Invoke a single presenter to show the contents of the catalog
|
||||
|
||||
A Scope object encapsulates the image object to be cataloged and the user options (catalog all layers vs. squashed layer),
|
||||
providing a way to inspect paths and file content within the image. The Scope object, not the image object, is used
|
||||
throughout the main execution path. This abstraction allows for decoupling of what is cataloged (a docker image, an OCI
|
||||
image, a filesystem, etc) and how it is cataloged (the individual catalogers).
|
||||
|
||||
Similar to the cataloging process, Linux distribution identification is also performed based on what is discovered within the image.
|
||||
*/
|
||||
package syft
|
||||
|
||||
@@ -10,35 +23,13 @@ import (
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/anchore/syft/syft/logger"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/plugin"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
PluginDirectory string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
config Config
|
||||
plugins *plugin.Repository
|
||||
}
|
||||
|
||||
func NewClient(config Config) (Client, error) {
|
||||
plugins, err := plugin.NewRepositoryFromDirectory(config.PluginDirectory)
|
||||
if err != nil {
|
||||
return Client{}, err
|
||||
}
|
||||
|
||||
return Client{
|
||||
config: config,
|
||||
plugins: plugins,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Catalog the given image from a particular perspective (e.g. squashed scope, all-layers scope). Returns the discovered
|
||||
// set of packages, the identified Linux distribution, and the scope object used to wrap the data source.
|
||||
func (c *Client) Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scope, *distro.Distro, error) {
|
||||
func Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scope, *distro.Distro, error) {
|
||||
log.Info("cataloging image")
|
||||
s, cleanup, err := scope.NewScope(userInput, scoptOpt)
|
||||
defer cleanup()
|
||||
@@ -46,9 +37,9 @@ func (c *Client) Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog,
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
d := c.IdentifyDistro(s)
|
||||
d := IdentifyDistro(s)
|
||||
|
||||
catalog, err := c.CatalogFromScope(s)
|
||||
catalog, err := CatalogFromScope(s)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@@ -58,7 +49,7 @@ func (c *Client) Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog,
|
||||
|
||||
// IdentifyDistro attempts to discover what the underlying Linux distribution may be from the available flat files
|
||||
// provided by the given scope object. If results are inconclusive a "UnknownDistro" Type is returned.
|
||||
func (c *Client) IdentifyDistro(s scope.Scope) distro.Distro {
|
||||
func IdentifyDistro(s scope.Scope) distro.Distro {
|
||||
d := distro.Identify(s.Resolver)
|
||||
if d.Type != distro.UnknownDistroType {
|
||||
log.Infof("identified distro: %s", d.String())
|
||||
@@ -69,15 +60,9 @@ func (c *Client) IdentifyDistro(s scope.Scope) distro.Distro {
|
||||
}
|
||||
|
||||
// Catalog the given scope, which may represent a container image or filesystem. Returns the discovered set of packages.
|
||||
func (c *Client) CatalogFromScope(s scope.Scope) (*pkg.Catalog, error) {
|
||||
func CatalogFromScope(s scope.Scope) (*pkg.Catalog, error) {
|
||||
log.Info("building the catalog")
|
||||
pluginCatalogers, deactivatePluginsFn, err := c.plugins.ActivateCatalogers()
|
||||
defer deactivatePluginsFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cataloger.Catalog(s.Resolver, append(pluginCatalogers, cataloger.BuiltIn()...)...)
|
||||
return cataloger.Catalog(s.Resolver, cataloger.All()...)
|
||||
}
|
||||
|
||||
// SetLogger sets the logger object used for all syft logging calls.
|
||||
@@ -5,7 +5,6 @@ package logger
|
||||
|
||||
type Logger interface {
|
||||
Errorf(format string, args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Info(args ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
// ApkMetadata represents all captured data for a Alpine DB package entry. See https://wiki.alpinelinux.org/wiki/Apk_spec for more information.
|
||||
type ApkMetadata struct {
|
||||
Package string `mapstructure:"P" json:"package"`
|
||||
OriginPackage string `mapstructure:"o" json:"origin-package"`
|
||||
OriginPackage string `mapstructure:"o" json:"originPackage"`
|
||||
Maintainer string `mapstructure:"m" json:"maintainer"`
|
||||
Version string `mapstructure:"V" json:"version"`
|
||||
License string `mapstructure:"L" json:"license"`
|
||||
@@ -15,18 +15,18 @@ type ApkMetadata struct {
|
||||
URL string `mapstructure:"U" json:"url"`
|
||||
Description string `mapstructure:"T" json:"description"`
|
||||
Size int `mapstructure:"S" json:"size"`
|
||||
InstalledSize int `mapstructure:"I" json:"installed-size"`
|
||||
PullDependencies string `mapstructure:"D" json:"pull-dependencies"`
|
||||
PullChecksum string `mapstructure:"C" json:"pull-checksum"`
|
||||
GitCommitOfAport string `mapstructure:"c" json:"git-commit-of-apk-port"`
|
||||
InstalledSize int `mapstructure:"I" json:"installedSize"`
|
||||
PullDependencies string `mapstructure:"D" json:"pullDependencies"`
|
||||
PullChecksum string `mapstructure:"C" json:"pullChecksum"`
|
||||
GitCommitOfAport string `mapstructure:"c" json:"gitCommitOfApkPort"`
|
||||
Files []ApkFileRecord `json:"files"`
|
||||
}
|
||||
|
||||
// ApkFileRecord represents a single file listing and metadata from a APK DB entry (which may have many of these file records).
|
||||
type ApkFileRecord struct {
|
||||
Path string `json:"path"`
|
||||
OwnerUID string `json:"owner-uid"`
|
||||
OwnerGUI string `json:"owner-gid"`
|
||||
OwnerUID string `json:"ownerUid"`
|
||||
OwnerGUI string `json:"ownerGid"`
|
||||
Permissions string `json:"permissions"`
|
||||
Checksum string `json:"checksum"`
|
||||
}
|
||||
|
||||
+13
-13
@@ -5,31 +5,31 @@ import "github.com/package-url/packageurl-go"
|
||||
// JavaMetadata encapsulates all Java ecosystem metadata for a package as well as an (optional) parent relationship.
|
||||
type JavaMetadata struct {
|
||||
Manifest *JavaManifest `mapstructure:"Manifest" json:"manifest"`
|
||||
PomProperties *PomProperties `mapstructure:"PomProperties" json:"pom-properties"`
|
||||
Parent *Package `json:"parent-package"` // TODO: should this be included in the json output?
|
||||
PomProperties *PomProperties `mapstructure:"PomProperties" json:"pomProperties"`
|
||||
Parent *Package `json:"parentPackage"` // TODO: should this be included in the json output?
|
||||
}
|
||||
|
||||
// PomProperties represents the fields of interest extracted from a Java archive's pom.xml file.
|
||||
type PomProperties struct {
|
||||
Path string
|
||||
Name string `mapstructure:"name" json:"name"`
|
||||
GroupID string `mapstructure:"groupId" json:"group-id"`
|
||||
ArtifactID string `mapstructure:"artifactId" json:"artifact-id"`
|
||||
GroupID string `mapstructure:"groupId" json:"groupId"`
|
||||
ArtifactID string `mapstructure:"artifactId" json:"artifactId"`
|
||||
Version string `mapstructure:"version" json:"version"`
|
||||
Extra map[string]string `mapstructure:",remain" json:"extra-fields"`
|
||||
Extra map[string]string `mapstructure:",remain" json:"extraFields"`
|
||||
}
|
||||
|
||||
// JavaManifest represents the fields of interest extracted from a Java archive's META-INF/MANIFEST.MF file.
|
||||
type JavaManifest struct {
|
||||
Name string `mapstructure:"Name" json:"name"`
|
||||
ManifestVersion string `mapstructure:"Manifest-Version" json:"manifest-version"`
|
||||
SpecTitle string `mapstructure:"Specification-Title" json:"specification-title"`
|
||||
SpecVersion string `mapstructure:"Specification-Version" json:"specification-version"`
|
||||
SpecVendor string `mapstructure:"Specification-Vendor" json:"specification-vendor"`
|
||||
ImplTitle string `mapstructure:"Implementation-Title" json:"implementation-title"`
|
||||
ImplVersion string `mapstructure:"Implementation-Version" json:"implementation-version"`
|
||||
ImplVendor string `mapstructure:"Implementation-Vendor" json:"implementation-vendor"`
|
||||
Extra map[string]string `mapstructure:",remain" json:"extra-fields"`
|
||||
ManifestVersion string `mapstructure:"Manifest-Version" json:"manifestVersion"`
|
||||
SpecTitle string `mapstructure:"Specification-Title" json:"specificationTitle"`
|
||||
SpecVersion string `mapstructure:"Specification-Version" json:"specificationVersion"`
|
||||
SpecVendor string `mapstructure:"Specification-Vendor" json:"specificationVendor"`
|
||||
ImplTitle string `mapstructure:"Implementation-Title" json:"implementationTitle"`
|
||||
ImplVersion string `mapstructure:"Implementation-Version" json:"implementationVersion"`
|
||||
ImplVendor string `mapstructure:"Implementation-Vendor" json:"implementationVendor"`
|
||||
Extra map[string]string `mapstructure:",remain" json:"extraFields"`
|
||||
}
|
||||
|
||||
func (m JavaMetadata) PackageURL() string {
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ type Package struct {
|
||||
id ID // uniquely identifies a package, set by the cataloger
|
||||
Name string `json:"manifest"` // the package name
|
||||
Version string `json:"version"` // the version of the package
|
||||
FoundBy string `json:"found-by"` // the specific cataloger that discovered this package
|
||||
FoundBy string `json:"foundBy"` // the specific cataloger that discovered this package
|
||||
Source []file.Reference `json:"sources"` // the locations that lead to the discovery of this package (note: this is not necessarily the locations that make up this package)
|
||||
// TODO: should we move licenses into metadata?
|
||||
Licenses []string `json:"licenses"` // licenses discovered with the package metadata
|
||||
|
||||
@@ -14,7 +14,7 @@ type RpmMetadata struct {
|
||||
Epoch int `json:"epoch"`
|
||||
Arch string `json:"architecture"`
|
||||
Release string `json:"release"`
|
||||
SourceRpm string `json:"source-rpm"`
|
||||
SourceRpm string `json:"sourceRpm"`
|
||||
Size int `json:"size"`
|
||||
License string `json:"license"`
|
||||
Vendor string `json:"vendor"`
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
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{}
|
||||
|
||||
// CatalogerPlugin is the implementation of plugin.Plugin that is served/consumed.
|
||||
type CatalogerPlugin struct {
|
||||
plugin.NetRPCUnsupportedPlugin
|
||||
Impl cataloger.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
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package plugin
|
||||
|
||||
type Config struct {
|
||||
Name string
|
||||
Type Type
|
||||
Command string
|
||||
Args []string
|
||||
Env []string
|
||||
Sha256 []byte
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/anchore/syft/syft/cataloger"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
var _ cataloger.Cataloger = &CatalogerClient{}
|
||||
|
||||
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) []file.Reference {
|
||||
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)
|
||||
|
||||
resp, err := c.client.SelectFiles(context.Background(), &proto.SelectFilesRequest{
|
||||
FileResolverBrokerId: brokerID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// TODO: nope
|
||||
panic(err)
|
||||
}
|
||||
|
||||
s.Stop()
|
||||
|
||||
var result []file.Reference
|
||||
for _, f := range resp.Files {
|
||||
result = append(result, file.NewFileReferenceWithID(file.Path(f.Path), uint64(f.Id)))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
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: results,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
log.Debugf("FilesByGlob Response: %+v", resp)
|
||||
|
||||
var result []file.Reference
|
||||
for _, ref := range resp.Files {
|
||||
result = append(result, file.NewFileReferenceWithID(file.Path(ref.Path), uint64(ref.Id)))
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/logger"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
)
|
||||
|
||||
var versionedPlugins = map[int]plugin.PluginSet{
|
||||
1: {
|
||||
TypeCataloger.String(): &CatalogerPlugin{},
|
||||
},
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
Config Config
|
||||
clientConfig plugin.ClientConfig
|
||||
client *plugin.Client
|
||||
}
|
||||
|
||||
// TODO: type should be in the name like with terraform "terraform-<TYPE>-<NAME>"
|
||||
|
||||
func NewPlugin(config Config) Plugin {
|
||||
//cmd := exec.Command("sh", "-c", config.Command) //, config.Args...)
|
||||
cmd := exec.Command(config.Command)
|
||||
cmd.Env = append(cmd.Env, config.Env...)
|
||||
|
||||
var secureConfig *plugin.SecureConfig
|
||||
if len(config.Sha256) > 0 {
|
||||
secureConfig = &plugin.SecureConfig{
|
||||
Checksum: config.Sha256,
|
||||
Hash: sha256.New(),
|
||||
}
|
||||
}
|
||||
|
||||
var pluginLogger hclog.Logger
|
||||
if logrusLogger, ok := log.Log.(*logger.LogrusLogger); ok {
|
||||
pluginLogger = logger.NewLogrusHCLogAdapter(logrusLogger.Logger, map[string]interface{}{"plugin": config.Name})
|
||||
} else {
|
||||
// TODO: this does not fully map features, thus logging will be awkward
|
||||
// TODO: find a better way to map loggers (expand our interface?)
|
||||
pluginLogger = logger.NewLoggerHCLogAdapter(log.Log)
|
||||
}
|
||||
|
||||
clientConfig := plugin.ClientConfig{
|
||||
HandshakeConfig: config.Type.HandshakeConfig(),
|
||||
VersionedPlugins: versionedPlugins,
|
||||
SecureConfig: secureConfig,
|
||||
Cmd: cmd,
|
||||
Logger: pluginLogger,
|
||||
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
|
||||
}
|
||||
@@ -1,841 +0,0 @@
|
||||
// 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",
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
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<string, string> 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);
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/cataloger"
|
||||
)
|
||||
|
||||
type Repository struct {
|
||||
byType map[Type][]Plugin
|
||||
}
|
||||
|
||||
func NewRepository() *Repository {
|
||||
return &Repository{
|
||||
byType: make(map[Type][]Plugin),
|
||||
}
|
||||
}
|
||||
|
||||
func NewRepositoryFromDirectory(dir string) (*Repository, error) {
|
||||
repo := NewRepository()
|
||||
if dir == "" {
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
return repo, repo.AddFromDirectory(dir)
|
||||
}
|
||||
|
||||
func (c *Repository) Add(plugin Plugin) {
|
||||
c.byType[plugin.Config.Type] = append(c.byType[plugin.Config.Type], plugin)
|
||||
}
|
||||
|
||||
func (c *Repository) AddFromDirectory(dir string, pluginTypes ...Type) error {
|
||||
plugins, err := Discover(dir, pluginTypes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, plugin := range plugins {
|
||||
log.Debugf("added plugin: %q", plugin.Config.Name)
|
||||
c.Add(plugin)
|
||||
}
|
||||
log.Debugf("%d plugins added", len(plugins))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Repository) Get(pluginType Type) []Plugin {
|
||||
return c.byType[pluginType]
|
||||
}
|
||||
|
||||
func (c *Repository) ActivateCatalogers() ([]cataloger.Cataloger, func(), error) {
|
||||
var result []cataloger.Cataloger
|
||||
var plugins []Plugin
|
||||
var deactivateFn = func() {
|
||||
for _, plugin := range plugins {
|
||||
if err := plugin.Stop(); err != nil {
|
||||
log.Errorf("failed to stop plugin: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, plugin := range c.Get(TypeCataloger) {
|
||||
raw, err := plugin.Start()
|
||||
if err != nil {
|
||||
return nil, deactivateFn, err
|
||||
}
|
||||
plugins = append(plugins, plugin)
|
||||
|
||||
theCataloger, ok := raw.(cataloger.Cataloger)
|
||||
if !ok {
|
||||
return nil, deactivateFn, fmt.Errorf("activation of cataloger did not return a cataloger object (name=%s type=%T)", plugin.Config.Name, theCataloger)
|
||||
}
|
||||
|
||||
result = append(result, theCataloger)
|
||||
}
|
||||
return result, deactivateFn, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
pluginPrefix := pluginType.String()
|
||||
pluginGlob := fmt.Sprintf("%s-*", pluginPrefix)
|
||||
paths, err := filepath.Glob(filepath.Join(dir, pluginGlob))
|
||||
|
||||
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: strings.TrimPrefix(filepath.Base(path), pluginPrefix+"-"),
|
||||
Type: pluginType,
|
||||
Command: path,
|
||||
Args: nil, // TODO
|
||||
Env: nil, // TODO
|
||||
}))
|
||||
}
|
||||
}
|
||||
return plugins, nil
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
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_PLUGIN_MAGIC_COOKIE",
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,6 @@ func (pres *Presenter) Present(output io.Writer) error {
|
||||
} else {
|
||||
imageID = src.Img.Metadata.Digest
|
||||
}
|
||||
src.Img.Metadata.Tags[0].TagStr()
|
||||
bom.BomDescriptor.Component = &BdComponent{
|
||||
Component: Component{
|
||||
Type: "container",
|
||||
|
||||
@@ -3,6 +3,7 @@ package cyclonedx
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"regexp"
|
||||
"testing"
|
||||
@@ -96,7 +97,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
catalog := pkg.NewCatalog()
|
||||
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-simple")
|
||||
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-simple")
|
||||
defer cleanup()
|
||||
|
||||
// populate catalog with test data
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:b3b1786a-2de3-4501-b902-58b701b8ad0e">
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:2bbada20-3e87-44ea-9a56-1aa0e4dd01a0">
|
||||
<components>
|
||||
<component type="library">
|
||||
<name>package1</name>
|
||||
@@ -21,7 +21,7 @@
|
||||
</component>
|
||||
</components>
|
||||
<bd:metadata>
|
||||
<bd:timestamp>2020-08-30T21:50:50-04:00</bd:timestamp>
|
||||
<bd:timestamp>2020-09-23T18:26:58-04:00</bd:timestamp>
|
||||
<bd:tool>
|
||||
<bd:vendor>anchore</bd:vendor>
|
||||
<bd:name>syft</bd:name>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:ab970429-e6a2-44a1-810c-f9ed2b7c3147">
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:94dae829-4d5d-482f-afab-27f43f919e2c">
|
||||
<components>
|
||||
<component type="library">
|
||||
<name>package1</name>
|
||||
@@ -21,14 +21,14 @@
|
||||
</component>
|
||||
</components>
|
||||
<bd:metadata>
|
||||
<bd:timestamp>2020-08-30T21:50:50-04:00</bd:timestamp>
|
||||
<bd:timestamp>2020-09-23T18:26:58-04:00</bd:timestamp>
|
||||
<bd:tool>
|
||||
<bd:vendor>anchore</bd:vendor>
|
||||
<bd:name>syft</bd:name>
|
||||
<bd:version>[not provided]</bd:version>
|
||||
</bd:tool>
|
||||
<bd:component type="container">
|
||||
<name>index.docker.io/library/anchore-fixture-image-simple</name>
|
||||
<name>index.docker.io/library/stereoscope-fixture-image-simple</name>
|
||||
<version>04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7</version>
|
||||
</bd:component>
|
||||
</bd:metadata>
|
||||
|
||||
@@ -9,7 +9,7 @@ type Artifact struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Type string `json:"type"`
|
||||
FoundBy []string `json:"found-by"`
|
||||
FoundBy []string `json:"foundBy"`
|
||||
Locations Locations `json:"locations,omitempty"`
|
||||
Metadata interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
)
|
||||
|
||||
type Document struct {
|
||||
Artifacts []Artifact `json:"artifacts"`
|
||||
Image *Image `json:"image,omitempty"`
|
||||
Directory *string `json:"directory,omitempty"`
|
||||
Source Source `json:"source"`
|
||||
}
|
||||
|
||||
func NewDocument(catalog *pkg.Catalog, s scope.Scope) (Document, error) {
|
||||
@@ -18,15 +15,11 @@ func NewDocument(catalog *pkg.Catalog, s scope.Scope) (Document, error) {
|
||||
Artifacts: make([]Artifact, 0),
|
||||
}
|
||||
|
||||
srcObj := s.Source()
|
||||
switch src := srcObj.(type) {
|
||||
case scope.ImageSource:
|
||||
doc.Image = NewImage(src)
|
||||
case scope.DirSource:
|
||||
doc.Directory = &s.DirSrc.Path
|
||||
default:
|
||||
return Document{}, fmt.Errorf("unsupported source: %T", src)
|
||||
src, err := NewSource(s)
|
||||
if err != nil {
|
||||
return Document{}, nil
|
||||
}
|
||||
doc.Source = src
|
||||
|
||||
for _, p := range catalog.Sorted() {
|
||||
art, err := NewArtifact(p, s)
|
||||
|
||||
@@ -6,12 +6,12 @@ type Image struct {
|
||||
Layers []Layer `json:"layers"`
|
||||
Size int64 `json:"size"`
|
||||
Digest string `json:"digest"`
|
||||
MediaType string `json:"media-type"`
|
||||
MediaType string `json:"mediaType"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
type Layer struct {
|
||||
MediaType string `json:"media-type"`
|
||||
MediaType string `json:"mediaType"`
|
||||
Digest string `json:"digest"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ type Locations interface{}
|
||||
|
||||
type ImageLocation struct {
|
||||
Path string `json:"path"`
|
||||
LayerIndex uint `json:"layer-index"`
|
||||
LayerIndex uint `json:"layerIndex"`
|
||||
}
|
||||
|
||||
func NewLocations(p *pkg.Package, s scope.Scope) (Locations, error) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/anchore/go-testutils"
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
@@ -72,11 +73,11 @@ func TestJsonImgsPresenter(t *testing.T) {
|
||||
testImage := "image-simple"
|
||||
|
||||
if *update {
|
||||
testutils.UpdateGoldenFixtureImage(t, testImage)
|
||||
imagetest.UpdateGoldenFixtureImage(t, testImage)
|
||||
}
|
||||
|
||||
catalog := pkg.NewCatalog()
|
||||
img := testutils.GetGoldenFixtureImage(t, testImage)
|
||||
img := imagetest.GetGoldenFixtureImage(t, testImage)
|
||||
|
||||
// populate catalog with test data
|
||||
catalog.Add(pkg.Package{
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
)
|
||||
|
||||
type Source struct {
|
||||
Type string `json:"type"`
|
||||
Target interface{} `json:"target"`
|
||||
}
|
||||
|
||||
func NewSource(s scope.Scope) (Source, error) {
|
||||
srcObj := s.Source()
|
||||
switch src := srcObj.(type) {
|
||||
case scope.ImageSource:
|
||||
return Source{
|
||||
Type: "image",
|
||||
Target: NewImage(src),
|
||||
}, nil
|
||||
case scope.DirSource:
|
||||
return Source{
|
||||
Type: "directory",
|
||||
Target: s.DirSrc.Path,
|
||||
}, nil
|
||||
default:
|
||||
return Source{}, fmt.Errorf("unsupported source: %T", src)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"name": "package-1",
|
||||
"version": "1.0.1",
|
||||
"type": "deb",
|
||||
"found-by": [
|
||||
"foundBy": [
|
||||
"the-cataloger-1"
|
||||
],
|
||||
"locations": [
|
||||
@@ -15,7 +15,7 @@
|
||||
"name": "package-2",
|
||||
"version": "2.0.1",
|
||||
"type": "deb",
|
||||
"found-by": [
|
||||
"foundBy": [
|
||||
"the-cataloger-2"
|
||||
],
|
||||
"locations": [
|
||||
@@ -23,5 +23,8 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"directory": "/some/path"
|
||||
"source": {
|
||||
"type": "directory",
|
||||
"target": "/some/path"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
"name": "package-1",
|
||||
"version": "1.0.1",
|
||||
"type": "deb",
|
||||
"found-by": [
|
||||
"foundBy": [
|
||||
"the-cataloger-1"
|
||||
],
|
||||
"locations": [
|
||||
{
|
||||
"path": "/somefile-1.txt",
|
||||
"layer-index": 0
|
||||
"layerIndex": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -18,40 +18,43 @@
|
||||
"name": "package-2",
|
||||
"version": "2.0.1",
|
||||
"type": "deb",
|
||||
"found-by": [
|
||||
"foundBy": [
|
||||
"the-cataloger-2"
|
||||
],
|
||||
"locations": [
|
||||
{
|
||||
"path": "/somefile-2.txt",
|
||||
"layer-index": 1
|
||||
"layerIndex": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"image": {
|
||||
"layers": [
|
||||
{
|
||||
"media-type": "application/vnd.docker.image.rootfs.diff.tar.gzip",
|
||||
"digest": "sha256:056c0789fa9ad629ceae6d09713fb035f84115af3c4a88a43aa60f13bc683053",
|
||||
"size": 22
|
||||
},
|
||||
{
|
||||
"media-type": "application/vnd.docker.image.rootfs.diff.tar.gzip",
|
||||
"digest": "sha256:b461c48116592c570a66fed71d5b09662a8172e168b7938cf317af47872cdc9b",
|
||||
"size": 16
|
||||
},
|
||||
{
|
||||
"media-type": "application/vnd.docker.image.rootfs.diff.tar.gzip",
|
||||
"digest": "sha256:00b80053e05c01da485015610d288ce3185fac00d251e2ada02b45a7a7c5f589",
|
||||
"size": 27
|
||||
}
|
||||
],
|
||||
"size": 65,
|
||||
"digest": "sha256:3c53d2d891940f8d8e95acb77b58752f54dc5de9d91d19dd90ced2db76256cea",
|
||||
"media-type": "application/vnd.docker.distribution.manifest.v2+json",
|
||||
"tags": [
|
||||
"anchore-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7"
|
||||
]
|
||||
"source": {
|
||||
"type": "image",
|
||||
"target": {
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
|
||||
"digest": "sha256:e158b57d6f5a96ef5fd22f2fe76c70b5ba6ff5b2619f9d83125b2aad0492ac7b",
|
||||
"size": 22
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
|
||||
"digest": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf",
|
||||
"size": 16
|
||||
},
|
||||
{
|
||||
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
|
||||
"digest": "sha256:f0e18aa6032c24659a9c741fc36ca56f589782ea132061ccf6f52b952403da94",
|
||||
"size": 27
|
||||
}
|
||||
],
|
||||
"size": 65,
|
||||
"digest": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368",
|
||||
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||||
"tags": [
|
||||
"stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
|
||||
@@ -50,6 +51,7 @@ func (pres *Presenter) Present(output io.Writer) error {
|
||||
}
|
||||
return false
|
||||
})
|
||||
rows = removeDuplicateRows(rows)
|
||||
|
||||
table := tablewriter.NewWriter(output)
|
||||
|
||||
@@ -71,3 +73,21 @@ func (pres *Presenter) Present(output io.Writer) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeDuplicateRows(items [][]string) [][]string {
|
||||
seen := map[string][]string{}
|
||||
// nolint:prealloc
|
||||
var result [][]string
|
||||
|
||||
for _, v := range items {
|
||||
key := strings.Join(v, "|")
|
||||
if seen[key] != nil {
|
||||
// dup!
|
||||
continue
|
||||
}
|
||||
|
||||
seen[key] = v
|
||||
result = append(result, v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ package table
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"github.com/go-test/deep"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/go-testutils"
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
@@ -20,7 +22,7 @@ func TestTablePresenter(t *testing.T) {
|
||||
testImage := "image-simple"
|
||||
|
||||
catalog := pkg.NewCatalog()
|
||||
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", testImage)
|
||||
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", testImage)
|
||||
defer cleanup()
|
||||
|
||||
// populate catalog with test data
|
||||
@@ -63,3 +65,32 @@ func TestTablePresenter(t *testing.T) {
|
||||
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveDuplicateRows(t *testing.T) {
|
||||
data := [][]string{
|
||||
{"1", "2", "3"},
|
||||
{"a", "b", "c"},
|
||||
{"1", "2", "3"},
|
||||
{"a", "b", "c"},
|
||||
{"1", "2", "3"},
|
||||
{"4", "5", "6"},
|
||||
{"1", "2", "1"},
|
||||
}
|
||||
|
||||
expected := [][]string{
|
||||
{"1", "2", "3"},
|
||||
{"a", "b", "c"},
|
||||
{"4", "5", "6"},
|
||||
{"1", "2", "1"},
|
||||
}
|
||||
|
||||
actual := removeDuplicateRows(data)
|
||||
|
||||
if diffs := deep.Equal(expected, actual); len(diffs) > 0 {
|
||||
t.Errorf("found diffs!")
|
||||
for _, d := range diffs {
|
||||
t.Errorf(" diff: %+v", d)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/anchore/go-testutils"
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
@@ -67,7 +68,7 @@ func TestTextImgPresenter(t *testing.T) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
catalog := pkg.NewCatalog()
|
||||
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-simple")
|
||||
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-simple")
|
||||
defer cleanup()
|
||||
|
||||
// populate catalog with test data
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
package scope
|
||||
|
||||
import "strings"
|
||||
|
||||
// Potentially consider moving this out into a generic package that parses user input.
|
||||
// Aside from scope, this is the 2nd package that looks at a string to parse the input
|
||||
// and return an Option type.
|
||||
|
||||
const (
|
||||
// nolint:varcheck,deadcode
|
||||
unknownProtocol protocolType = iota
|
||||
imageProtocol
|
||||
directoryProtocol
|
||||
)
|
||||
|
||||
var protocolStr = []string{
|
||||
"UnknownProtocol",
|
||||
"Image",
|
||||
"Directory",
|
||||
}
|
||||
|
||||
type protocolType int
|
||||
|
||||
type protocol struct {
|
||||
Type protocolType
|
||||
Value string
|
||||
}
|
||||
|
||||
func newProtocol(userStr string) protocol {
|
||||
candidates := strings.Split(userStr, "://")
|
||||
|
||||
switch len(candidates) {
|
||||
case 2:
|
||||
if strings.HasPrefix(userStr, "dir://") {
|
||||
return protocol{
|
||||
Type: directoryProtocol,
|
||||
Value: strings.TrimPrefix(userStr, "dir://"),
|
||||
}
|
||||
}
|
||||
// default to an Image for anything else since stereoscope can handle this
|
||||
return protocol{
|
||||
Type: imageProtocol,
|
||||
Value: userStr,
|
||||
}
|
||||
default:
|
||||
return protocol{
|
||||
Type: imageProtocol,
|
||||
Value: userStr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o protocolType) String() string {
|
||||
if int(o) >= len(protocolStr) || o < 0 {
|
||||
return protocolStr[0]
|
||||
}
|
||||
|
||||
return protocolStr[o]
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package scope
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNewProtocol(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
input string
|
||||
expType protocolType
|
||||
expValue string
|
||||
}{
|
||||
{
|
||||
desc: "directory protocol",
|
||||
input: "dir:///opt/",
|
||||
expType: directoryProtocol,
|
||||
expValue: "/opt/",
|
||||
},
|
||||
{
|
||||
desc: "unknown protocol",
|
||||
input: "s4:///opt/",
|
||||
expType: imageProtocol,
|
||||
expValue: "s4:///opt/",
|
||||
},
|
||||
{
|
||||
desc: "docker protocol",
|
||||
input: "docker://ubuntu:20.04",
|
||||
expType: imageProtocol,
|
||||
expValue: "docker://ubuntu:20.04",
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
p := newProtocol(test.input)
|
||||
if p.Type != test.expType {
|
||||
t.Errorf("mismatched type in protocol: '%v' != '%v'", p.Type, test.expType)
|
||||
}
|
||||
if p.Value != test.expValue {
|
||||
t.Errorf("mismatched protocol value: '%s' != '%s'", p.Value, test.expValue)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package scope
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/image"
|
||||
@@ -17,7 +16,7 @@ type Resolver interface {
|
||||
|
||||
// ContentResolver knows how to get file content for given file.References
|
||||
type ContentResolver interface {
|
||||
MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]io.Reader, error)
|
||||
MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]string, error)
|
||||
}
|
||||
|
||||
// FileResolver knows how to get file.References for given string paths and globs
|
||||
|
||||
@@ -3,7 +3,6 @@ package resolvers
|
||||
import (
|
||||
"archive/tar"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/image"
|
||||
@@ -112,6 +111,6 @@ func (r *AllLayersResolver) FilesByGlob(patterns ...string) ([]file.Reference, e
|
||||
|
||||
// MultipleFileContentsByRef returns the file contents for all file.References relative to the image. Note that a
|
||||
// file.Reference is a path relative to a particular layer.
|
||||
func (r *AllLayersResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]io.Reader, error) {
|
||||
func (r *AllLayersResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]string, error) {
|
||||
return r.img.MultipleFileContentsByRef(f...)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package resolvers
|
||||
|
||||
import (
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/go-testutils"
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
)
|
||||
|
||||
@@ -83,7 +83,7 @@ func TestAllLayersResolver_FilesByPath(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-symlinks")
|
||||
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks")
|
||||
defer cleanup()
|
||||
|
||||
resolver, err := NewAllLayersResolver(img)
|
||||
@@ -191,7 +191,7 @@ func TestAllLayersResolver_FilesByGlob(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-symlinks")
|
||||
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks")
|
||||
defer cleanup()
|
||||
|
||||
resolver, err := NewAllLayersResolver(img)
|
||||
|
||||
@@ -2,7 +2,7 @@ package resolvers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
@@ -40,6 +40,15 @@ func (s DirectoryResolver) FilesByPath(userPaths ...file.Path) ([]file.Reference
|
||||
return references, nil
|
||||
}
|
||||
|
||||
func fileContents(path file.Path) ([]byte, error) {
|
||||
contents, err := ioutil.ReadFile(string(path))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
// FilesByGlob returns all file.References that match the given path glob pattern from any layer in the image.
|
||||
func (s DirectoryResolver) FilesByGlob(patterns ...string) ([]file.Reference, error) {
|
||||
result := make([]file.Reference, 0)
|
||||
@@ -67,15 +76,15 @@ func (s DirectoryResolver) FilesByGlob(patterns ...string) ([]file.Reference, er
|
||||
}
|
||||
|
||||
// MultipleFileContentsByRef returns the file contents for all file.References relative a directory.
|
||||
func (s DirectoryResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]io.Reader, error) {
|
||||
refContents := make(map[file.Reference]io.Reader)
|
||||
func (s DirectoryResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]string, error) {
|
||||
refContents := make(map[file.Reference]string)
|
||||
for _, fileRef := range f {
|
||||
targetFile, err := os.Open(string(fileRef.Path))
|
||||
if err != nil {
|
||||
return refContents, fmt.Errorf("could not open file=%q: %w", fileRef.Path, err)
|
||||
}
|
||||
contents, err := fileContents(fileRef.Path)
|
||||
|
||||
refContents[fileRef] = targetFile
|
||||
if err != nil {
|
||||
return refContents, fmt.Errorf("could not read contents of file: %s", fileRef.Path)
|
||||
}
|
||||
refContents[fileRef] = string(contents)
|
||||
}
|
||||
return refContents, nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package resolvers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/image"
|
||||
@@ -76,6 +75,6 @@ func (r *ImageSquashResolver) FilesByGlob(patterns ...string) ([]file.Reference,
|
||||
|
||||
// MultipleFileContentsByRef returns the file contents for all file.References relative to the image. Note that a
|
||||
// file.Reference is a path relative to a particular layer, in this case only from the squashed representation.
|
||||
func (r *ImageSquashResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]io.Reader, error) {
|
||||
func (r *ImageSquashResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]string, error) {
|
||||
return r.img.MultipleFileContentsByRef(f...)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package resolvers
|
||||
|
||||
import (
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/go-testutils"
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
)
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestImageSquashResolver_FilesByPath(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-symlinks")
|
||||
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks")
|
||||
defer cleanup()
|
||||
|
||||
resolver, err := NewImageSquashResolver(img)
|
||||
@@ -122,7 +122,7 @@ func TestImageSquashResolver_FilesByGlob(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-symlinks")
|
||||
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks")
|
||||
defer cleanup()
|
||||
|
||||
resolver, err := NewImageSquashResolver(img)
|
||||
|
||||
+55
-22
@@ -7,7 +7,10 @@ package scope
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/spf13/afero"
|
||||
|
||||
"github.com/anchore/stereoscope"
|
||||
|
||||
@@ -15,6 +18,14 @@ import (
|
||||
"github.com/anchore/syft/syft/scope/resolvers"
|
||||
)
|
||||
|
||||
const (
|
||||
unknownScheme scheme = "unknown-scheme"
|
||||
directoryScheme scheme = "directory-scheme"
|
||||
imageScheme scheme = "image-scheme"
|
||||
)
|
||||
|
||||
type scheme string
|
||||
|
||||
// ImageSource represents a data source that is a container image
|
||||
type ImageSource struct {
|
||||
Img *image.Image // the image object to be cataloged
|
||||
@@ -34,31 +45,36 @@ type Scope struct {
|
||||
DirSrc DirSource // the specific directory to be cataloged
|
||||
}
|
||||
|
||||
// NewScope produces a Scope based on userInput like dir:// or image:tag
|
||||
// NewScope produces a Scope based on userInput like dir: or image:tag
|
||||
func NewScope(userInput string, o Option) (Scope, func(), error) {
|
||||
protocol := newProtocol(userInput)
|
||||
fs := afero.NewOsFs()
|
||||
parsedScheme, location := detectScheme(fs, image.DetectSource, userInput)
|
||||
|
||||
switch protocol.Type {
|
||||
case directoryProtocol:
|
||||
err := isValidPath(protocol.Value)
|
||||
switch parsedScheme {
|
||||
case directoryScheme:
|
||||
fileMeta, err := fs.Stat(location)
|
||||
if err != nil {
|
||||
return Scope{}, func() {}, fmt.Errorf("unable to process path, must exist and be a directory: %w", err)
|
||||
return Scope{}, func() {}, fmt.Errorf("unable to stat dir=%q: %w", location, err)
|
||||
}
|
||||
|
||||
s, err := NewScopeFromDir(protocol.Value)
|
||||
if !fileMeta.IsDir() {
|
||||
return Scope{}, func() {}, fmt.Errorf("given path is not a directory (path=%q): %w", location, err)
|
||||
}
|
||||
|
||||
s, err := NewScopeFromDir(location)
|
||||
if err != nil {
|
||||
return Scope{}, func() {}, fmt.Errorf("could not populate scope from path (%s): %w", protocol.Value, err)
|
||||
return Scope{}, func() {}, fmt.Errorf("could not populate scope from path=%q: %w", location, err)
|
||||
}
|
||||
return s, func() {}, nil
|
||||
|
||||
case imageProtocol:
|
||||
img, err := stereoscope.GetImage(userInput)
|
||||
case imageScheme:
|
||||
img, err := stereoscope.GetImage(location)
|
||||
cleanup := func() {
|
||||
stereoscope.Cleanup()
|
||||
}
|
||||
|
||||
if err != nil || img == nil {
|
||||
return Scope{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", userInput, err)
|
||||
return Scope{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", location, err)
|
||||
}
|
||||
|
||||
s, err := NewScopeFromImage(img, o)
|
||||
@@ -66,10 +82,9 @@ func NewScope(userInput string, o Option) (Scope, func(), error) {
|
||||
return Scope{}, cleanup, fmt.Errorf("could not populate scope with image: %w", err)
|
||||
}
|
||||
return s, cleanup, nil
|
||||
|
||||
default:
|
||||
return Scope{}, func() {}, fmt.Errorf("unable to process input for scanning: '%s'", userInput)
|
||||
}
|
||||
|
||||
return Scope{}, func() {}, fmt.Errorf("unable to process input for scanning: '%s'", userInput)
|
||||
}
|
||||
|
||||
// NewScopeFromDir creates a new scope object tailored to catalog a given filesystem directory recursively.
|
||||
@@ -117,16 +132,34 @@ func (s Scope) Source() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// isValidPath ensures that the user-provided input will correspond to a path that exists and is a directory
|
||||
func isValidPath(userInput string) error {
|
||||
fileMeta, err := os.Stat(userInput)
|
||||
type sourceDetector func(string) (image.Source, string, error)
|
||||
|
||||
func detectScheme(fs afero.Fs, imageDetector sourceDetector, userInput string) (scheme, string) {
|
||||
if strings.HasPrefix(userInput, "dir:") {
|
||||
// blindly trust the user's scheme
|
||||
return directoryScheme, strings.TrimPrefix(userInput, "dir:")
|
||||
}
|
||||
|
||||
// we should attempt to let stereoscope determine what the source is first --just because the source is a valid directory
|
||||
// doesn't mean we yet know if it is an OCI layout directory (to be treated as an image) or if it is a generic filesystem directory.
|
||||
source, imageSpec, err := imageDetector(userInput)
|
||||
if err != nil {
|
||||
return err
|
||||
// this is not necessarily an error we care a
|
||||
log.Debugf("unable to detect the scheme from %q: %w", userInput, err)
|
||||
return unknownScheme, ""
|
||||
}
|
||||
|
||||
if fileMeta.IsDir() {
|
||||
return nil
|
||||
if source == image.UnknownSource {
|
||||
fileMeta, err := fs.Stat(userInput)
|
||||
if err != nil {
|
||||
return unknownScheme, ""
|
||||
}
|
||||
|
||||
if fileMeta.IsDir() {
|
||||
return directoryScheme, userInput
|
||||
}
|
||||
return unknownScheme, ""
|
||||
}
|
||||
|
||||
return fmt.Errorf("path is not a directory: %s", userInput)
|
||||
return imageScheme, imageSpec
|
||||
}
|
||||
|
||||
+165
-19
@@ -1,6 +1,8 @@
|
||||
package scope
|
||||
|
||||
import (
|
||||
"github.com/spf13/afero"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
@@ -214,39 +216,183 @@ func TestFilesByGlob(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValidPath(t *testing.T) {
|
||||
func TestDetectScheme(t *testing.T) {
|
||||
type detectorResult struct {
|
||||
src image.Source
|
||||
ref string
|
||||
err error
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
input string
|
||||
isError bool
|
||||
name string
|
||||
userInput string
|
||||
dirs []string
|
||||
detection detectorResult
|
||||
expectedScheme scheme
|
||||
expectedLocation string
|
||||
}{
|
||||
{
|
||||
desc: "path is valid",
|
||||
input: "test-fixtures",
|
||||
isError: false,
|
||||
name: "docker-image-ref",
|
||||
userInput: "wagoodman/dive:latest",
|
||||
detection: detectorResult{
|
||||
src: image.DockerDaemonSource,
|
||||
ref: "wagoodman/dive:latest",
|
||||
},
|
||||
expectedScheme: imageScheme,
|
||||
expectedLocation: "wagoodman/dive:latest",
|
||||
},
|
||||
{
|
||||
desc: "file is invalid",
|
||||
input: "test-fixtures/.vimrc",
|
||||
isError: true,
|
||||
name: "docker-image-ref-no-tag",
|
||||
userInput: "wagoodman/dive",
|
||||
detection: detectorResult{
|
||||
src: image.DockerDaemonSource,
|
||||
ref: "wagoodman/dive",
|
||||
},
|
||||
expectedScheme: imageScheme,
|
||||
expectedLocation: "wagoodman/dive",
|
||||
},
|
||||
{
|
||||
desc: "path does not exist",
|
||||
input: "foo/bar/baz",
|
||||
isError: true,
|
||||
name: "docker-image-explicit-scheme",
|
||||
userInput: "docker:wagoodman/dive:latest",
|
||||
detection: detectorResult{
|
||||
src: image.DockerDaemonSource,
|
||||
ref: "wagoodman/dive:latest",
|
||||
},
|
||||
expectedScheme: imageScheme,
|
||||
expectedLocation: "wagoodman/dive:latest",
|
||||
},
|
||||
{
|
||||
name: "docker-image-explicit-scheme-no-tag",
|
||||
userInput: "docker:wagoodman/dive",
|
||||
detection: detectorResult{
|
||||
src: image.DockerDaemonSource,
|
||||
ref: "wagoodman/dive",
|
||||
},
|
||||
expectedScheme: imageScheme,
|
||||
expectedLocation: "wagoodman/dive",
|
||||
},
|
||||
{
|
||||
name: "docker-image-edge-case",
|
||||
userInput: "docker:latest",
|
||||
detection: detectorResult{
|
||||
src: image.DockerDaemonSource,
|
||||
ref: "latest",
|
||||
},
|
||||
expectedScheme: imageScheme,
|
||||
// we want to be able to handle this case better, however, I don't see a way to do this
|
||||
// the user will need to provide more explicit input (docker:docker:latest)
|
||||
expectedLocation: "latest",
|
||||
},
|
||||
{
|
||||
name: "docker-image-edge-case-explicit",
|
||||
userInput: "docker:docker:latest",
|
||||
detection: detectorResult{
|
||||
src: image.DockerDaemonSource,
|
||||
ref: "docker:latest",
|
||||
},
|
||||
expectedScheme: imageScheme,
|
||||
// we want to be able to handle this case better, however, I don't see a way to do this
|
||||
// the user will need to provide more explicit input (docker:docker:latest)
|
||||
expectedLocation: "docker:latest",
|
||||
},
|
||||
{
|
||||
name: "oci-tar",
|
||||
userInput: "some/path-to-file",
|
||||
detection: detectorResult{
|
||||
src: image.OciTarballSource,
|
||||
ref: "some/path-to-file",
|
||||
},
|
||||
expectedScheme: imageScheme,
|
||||
expectedLocation: "some/path-to-file",
|
||||
},
|
||||
{
|
||||
name: "oci-dir",
|
||||
userInput: "some/path-to-dir",
|
||||
detection: detectorResult{
|
||||
src: image.OciDirectorySource,
|
||||
ref: "some/path-to-dir",
|
||||
},
|
||||
dirs: []string{"some/path-to-dir"},
|
||||
expectedScheme: imageScheme,
|
||||
expectedLocation: "some/path-to-dir",
|
||||
},
|
||||
{
|
||||
name: "guess-dir",
|
||||
userInput: "some/path-to-dir",
|
||||
detection: detectorResult{
|
||||
src: image.UnknownSource,
|
||||
ref: "",
|
||||
},
|
||||
dirs: []string{"some/path-to-dir"},
|
||||
expectedScheme: directoryScheme,
|
||||
expectedLocation: "some/path-to-dir",
|
||||
},
|
||||
{
|
||||
name: "generic-dir-does-not-exist",
|
||||
userInput: "some/path-to-dir",
|
||||
detection: detectorResult{
|
||||
src: image.DockerDaemonSource,
|
||||
ref: "some/path-to-dir",
|
||||
},
|
||||
expectedScheme: imageScheme,
|
||||
expectedLocation: "some/path-to-dir",
|
||||
},
|
||||
{
|
||||
name: "explicit-dir",
|
||||
userInput: "dir:some/path-to-dir",
|
||||
detection: detectorResult{
|
||||
src: image.UnknownSource,
|
||||
ref: "",
|
||||
},
|
||||
dirs: []string{"some/path-to-dir"},
|
||||
expectedScheme: directoryScheme,
|
||||
expectedLocation: "some/path-to-dir",
|
||||
},
|
||||
{
|
||||
name: "explicit-current-dir",
|
||||
userInput: "dir:.",
|
||||
detection: detectorResult{
|
||||
src: image.UnknownSource,
|
||||
ref: "",
|
||||
},
|
||||
expectedScheme: directoryScheme,
|
||||
expectedLocation: ".",
|
||||
},
|
||||
{
|
||||
name: "current-dir",
|
||||
userInput: ".",
|
||||
detection: detectorResult{
|
||||
src: image.UnknownSource,
|
||||
ref: "",
|
||||
},
|
||||
expectedScheme: directoryScheme,
|
||||
expectedLocation: ".",
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
err := isValidPath(test.input)
|
||||
if err != nil && !test.isError {
|
||||
t.Errorf("did not expect and error, got: %w", err)
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
fs := afero.NewMemMapFs()
|
||||
|
||||
for _, p := range test.dirs {
|
||||
err := fs.Mkdir(p, os.ModePerm)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create dummy tar: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && test.isError {
|
||||
t.Errorf("expected an error but didn't get one")
|
||||
imageDetector := func(string) (image.Source, string, error) {
|
||||
return test.detection.src, test.detection.ref, test.detection.err
|
||||
}
|
||||
|
||||
actualScheme, actualLocation := detectScheme(fs, imageDetector, test.userInput)
|
||||
|
||||
if actualScheme != test.expectedScheme {
|
||||
t.Errorf("expected scheme %q , got %q", test.expectedScheme, actualScheme)
|
||||
}
|
||||
|
||||
if actualLocation != test.expectedLocation {
|
||||
t.Errorf("expected location %q , got %q", test.expectedLocation, actualLocation)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ function cleanup {
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
# install skopeo (pinned to 1.1.0)
|
||||
skopeo --version || brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/75e8d7a40af77b48cc91f4bdb7d669f891a6de60/Formula/skopeo.rb
|
||||
# install skopeo
|
||||
skopeo --version || brew install skopeo
|
||||
|
||||
# fetch test image
|
||||
skopeo --override-os linux copy docker://docker.io/${TEST_IMAGE} docker-archive:${TEST_IMAGE_TAR}
|
||||
|
||||
@@ -5,9 +5,8 @@ package integration
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"github.com/anchore/syft/syft"
|
||||
|
||||
"github.com/anchore/go-testutils"
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"github.com/go-test/deep"
|
||||
@@ -15,11 +14,11 @@ import (
|
||||
|
||||
func TestDistroImage(t *testing.T) {
|
||||
fixtureImageName := "image-distro-id"
|
||||
_, cleanup := testutils.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
||||
tarPath := testutils.GetFixtureImageTarPath(t, fixtureImageName)
|
||||
_, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
||||
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
|
||||
defer cleanup()
|
||||
|
||||
_, _, actualDistro, err := syft.Catalog("docker-archive://"+tarPath, scope.AllLayersScope)
|
||||
_, _, actualDistro, err := syft.Catalog("docker-archive:"+tarPath, scope.AllLayersScope)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to catalog image: %+v", err)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/go-testutils"
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"github.com/anchore/syft/syft"
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -99,11 +99,11 @@ func testJsonSchema(t *testing.T, catalog *pkg.Catalog, theScope *scope.Scope, p
|
||||
|
||||
func TestJsonSchemaImg(t *testing.T) {
|
||||
fixtureImageName := "image-pkg-coverage"
|
||||
_, cleanup := testutils.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
||||
tarPath := testutils.GetFixtureImageTarPath(t, fixtureImageName)
|
||||
_, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
||||
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
|
||||
defer cleanup()
|
||||
|
||||
catalog, theScope, _, err := syft.Catalog("docker-archive://"+tarPath, scope.AllLayersScope)
|
||||
catalog, theScope, _, err := syft.Catalog("docker-archive:"+tarPath, scope.AllLayersScope)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to catalog image: %+v", err)
|
||||
}
|
||||
@@ -116,7 +116,7 @@ func TestJsonSchemaImg(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestJsonSchemaDirs(t *testing.T) {
|
||||
catalog, theScope, _, err := syft.Catalog("dir://test-fixtures/image-pkg-coverage", scope.AllLayersScope)
|
||||
catalog, theScope, _, err := syft.Catalog("dir:test-fixtures/image-pkg-coverage", scope.AllLayersScope)
|
||||
if err != nil {
|
||||
t.Errorf("unable to create scope from dir: %+v", err)
|
||||
}
|
||||
|
||||
@@ -81,7 +81,13 @@ var cases = []struct {
|
||||
pkgType: pkg.PythonRequirementsPkg,
|
||||
pkgLanguage: pkg.Python,
|
||||
pkgInfo: map[string]string{
|
||||
"flask": "4.0.0",
|
||||
"flask": "4.0.0",
|
||||
"python-dateutil": "2.8.1",
|
||||
"python-swiftclient": "3.8.1",
|
||||
"pytz": "2019.3",
|
||||
"jsonschema": "2.6.0",
|
||||
"passlib": "1.7.2",
|
||||
"pathlib": "1.0.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3,24 +3,22 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
|
||||
"github.com/anchore/go-testutils"
|
||||
"github.com/anchore/syft/syft"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
)
|
||||
|
||||
func TestPkgCoverageImage(t *testing.T) {
|
||||
fixtureImageName := "image-pkg-coverage"
|
||||
_, cleanup := testutils.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
||||
tarPath := testutils.GetFixtureImageTarPath(t, fixtureImageName)
|
||||
_, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
|
||||
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
|
||||
defer cleanup()
|
||||
|
||||
catalog, _, _, err := syft.Catalog("docker-archive://"+tarPath, scope.AllLayersScope)
|
||||
catalog, _, _, err := syft.Catalog("docker-archive:"+tarPath, scope.AllLayersScope)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to catalog image: %+v", err)
|
||||
}
|
||||
@@ -91,7 +89,7 @@ func TestPkgCoverageImage(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPkgCoverageDirectory(t *testing.T) {
|
||||
catalog, _, _, err := syft.Catalog("dir://test-fixtures/image-pkg-coverage", scope.AllLayersScope)
|
||||
catalog, _, _, err := syft.Catalog("dir:test-fixtures/image-pkg-coverage", scope.AllLayersScope)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("unable to create scope from dir: %+v", err)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
jsonschema==2.6.0
|
||||
passlib==1.7.2
|
||||
pathlib==1.0.1
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
python-dateutil==2.8.1
|
||||
python-swiftclient==3.8.1
|
||||
pytz==2019.3
|
||||
Reference in New Issue
Block a user