Skip to content

Commit

Permalink
packages lib support test
Browse files Browse the repository at this point in the history
  • Loading branch information
houdini91 committed Apr 17, 2022
1 parent b46d044 commit 5cf3da8
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 72 deletions.
Binary file added cmd/__debug_bin
Binary file not shown.
13 changes: 7 additions & 6 deletions cmd/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"strings"

"github.com/anchore/syft/internal/config"
"github.com/anchore/syft/internal/formats/cyclonedxjson"
"github.com/anchore/syft/internal/formats/spdx22json"
"github.com/anchore/syft/internal/formats/syftjson"
Expand Down Expand Up @@ -84,7 +85,7 @@ var (
defer profile.Start(profile.MemProfile).Stop()
}

return attestExec(cmd.Context(), cmd, args)
return attestExec(cmd.Context(), cmd, args, appConfig)
},
}
)
Expand Down Expand Up @@ -128,7 +129,7 @@ func selectPassFunc(keypath string) (cosign.PassFunc, error) {
return fn, nil
}

func attestExec(ctx context.Context, _ *cobra.Command, args []string) error {
func attestExec(ctx context.Context, _ *cobra.Command, args []string, cfg *config.Application) error {
// can only be an image for attestation or OCI DIR
userInput := args[0]
si, err := source.ParseInput(userInput, appConfig.Platform, false)
Expand Down Expand Up @@ -180,15 +181,15 @@ func attestExec(ctx context.Context, _ *cobra.Command, args []string) error {
defer sv.Close()

return eventLoop(
attestationExecWorker(*si, format, predicateType, sv),
attestationExecWorker(*si, cfg, format, predicateType, sv),
setupSignals(),
eventSubscription,
stereoscope.Cleanup,
ui.Select(isVerbose(), appConfig.Quiet)...,
ui.Select(isVerbose(appConfig), appConfig.Quiet)...,
)
}

func attestationExecWorker(sourceInput source.Input, format sbom.Format, predicateType string, sv *sign.SignerVerifier) <-chan error {
func attestationExecWorker(sourceInput source.Input, cfg *config.Application, format sbom.Format, predicateType string, sv *sign.SignerVerifier) <-chan error {
errs := make(chan error)
go func() {
defer close(errs)
Expand All @@ -202,7 +203,7 @@ func attestationExecWorker(sourceInput source.Input, format sbom.Format, predica
return
}

s, err := generateSBOM(src, errs)
s, err := generateSBOM(src, cfg, errs)
if err != nil {
errs <- err
return
Expand Down
15 changes: 10 additions & 5 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/anchore/syft/internal/logger"
"github.com/anchore/syft/internal/version"
"github.com/anchore/syft/syft"

"github.com/gookit/color"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -113,12 +114,16 @@ func initAppConfig() {
}

func initLogging() {
initLoggingConfig(appConfig)
}

func initLoggingConfig(appCfg *config.Application) {
cfg := logger.LogrusConfig{
EnableConsole: (appConfig.Log.FileLocation == "" || appConfig.CliOptions.Verbosity > 0) && !appConfig.Quiet,
EnableFile: appConfig.Log.FileLocation != "",
Level: appConfig.Log.LevelOpt,
Structured: appConfig.Log.Structured,
FileLocation: appConfig.Log.FileLocation,
EnableConsole: (appCfg.Log.FileLocation == "" || appCfg.CliOptions.Verbosity > 0) && !appCfg.Quiet,
EnableFile: appCfg.Log.FileLocation != "",
Level: appCfg.Log.LevelOpt,
Structured: appCfg.Log.Structured,
FileLocation: appCfg.Log.FileLocation,
}

logWrapper := logger.NewLogrusLogger(cfg)
Expand Down
101 changes: 101 additions & 0 deletions cmd/lib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package cmd

import (
"fmt"
"os"

"github.com/anchore/stereoscope"
"github.com/anchore/syft/internal/config"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/ui"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/logger"
syftLogger "github.com/anchore/syft/syft/logger"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
"github.com/wagoodman/go-partybus"
)

func LibInitBase(cfg *config.Application, l logger.Logger, enable_ui bool) ([]ui.UI, error) {
if err := cfg.LibParseConfigValues(); err != nil {
return nil, fmt.Errorf("invalid application config: %w", err)
}

var uis []ui.UI
uis = append(uis, ui.NewlibUI())
if l == nil {
initLoggingConfig(cfg)
uis = ui.Select(isVerbose(cfg), cfg.Quiet)
} else {
libInitLoggingConfig(l)
uis = append(uis, ui.NewLoggerUI())
}

if enable_ui {
uis = ui.Select(isVerbose(cfg), cfg.Quiet)
}

return uis, nil
}

func libInitLoggingConfig(logWrapper syftLogger.Logger) {
syft.SetLogger(logWrapper)
stereoscope.SetLogger(logWrapper)
}

func libInitEventBus() {
if eventSubscription == nil {
initEventBus()
}
}

func LibPackagesExec(userInput string, cfg *config.Application, l logger.Logger, enable_ui bool) (*sbom.SBOM, error) {
writer, err := makeWriter(cfg.Outputs, cfg.File)
if err != nil {
return nil, err
}

uis, err := LibInitBase(cfg, l, enable_ui)
if err != nil {
return nil, err
}

defer func() {
if err := writer.Close(); err != nil {
log.Warnf("unable to write to report destination: %w", err)
}
}()

// could be an image or a directory, with or without a scheme
si, err := source.ParseInput(userInput, cfg.Platform, true)
if err != nil {
return nil, fmt.Errorf("could not generate source input for packages command: %w", err)
}

libInitEventBus()
outSbom, errs := packagesExecWorker(*si, cfg, writer)
return SbomEventLoop(
outSbom, errs,
setupSignals(),
eventSubscription,
stereoscope.Cleanup,
uis...,
)
}

func SbomEventLoop(outSbom <-chan *sbom.SBOM, workerErrs <-chan error, signals <-chan os.Signal, subscription *partybus.Subscription, cleanupFn func(), uxs ...ui.UI) (*sbom.SBOM, error) {
err := eventLoop(workerErrs,
signals,
subscription,
cleanupFn,
uxs...)

var out *sbom.SBOM
if err == nil {
out = <-outSbom
}
// out := <-outSbom

return out, err

}
72 changes: 41 additions & 31 deletions cmd/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/anchore"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/config"
"github.com/anchore/syft/internal/formats/table"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/ui"
Expand Down Expand Up @@ -82,7 +83,7 @@ var (
defer profile.Start(profile.MemProfile).Stop()
}

return packagesExec(cmd, args)
return packagesExec(cmd, args, appConfig)
},
ValidArgsFunction: dockerImageValidArgsFunction,
}
Expand Down Expand Up @@ -221,8 +222,8 @@ func validateInputArgs(cmd *cobra.Command, args []string) error {
return cobra.MaximumNArgs(1)(cmd, args)
}

func packagesExec(_ *cobra.Command, args []string) error {
writer, err := makeWriter(appConfig.Outputs, appConfig.File)
func packagesExec(_ *cobra.Command, args []string, cfg *config.Application) error {
writer, err := makeWriter(cfg.Outputs, cfg.File)
if err != nil {
return err
}
Expand All @@ -235,33 +236,35 @@ func packagesExec(_ *cobra.Command, args []string) error {

// could be an image or a directory, with or without a scheme
userInput := args[0]
si, err := source.ParseInput(userInput, appConfig.Platform, true)
si, err := source.ParseInput(userInput, cfg.Platform, true)
if err != nil {
return fmt.Errorf("could not generate source input for packages command: %w", err)
}

_, errs := packagesExecWorker(*si, cfg, writer)

return eventLoop(
packagesExecWorker(*si, writer),
errs,
setupSignals(),
eventSubscription,
stereoscope.Cleanup,
ui.Select(isVerbose(), appConfig.Quiet)...,
ui.Select(isVerbose(cfg), cfg.Quiet)...,
)
}

func isVerbose() (result bool) {
func isVerbose(cfg *config.Application) (result bool) {
isPipedInput, err := internal.IsPipedInput()
if err != nil {
// since we can't tell if there was piped input we assume that there could be to disable the ETUI
log.Warnf("unable to determine if there is piped input: %+v", err)
return true
}
// verbosity should consider if there is piped input (in which case we should not show the ETUI)
return appConfig.CliOptions.Verbosity > 0 || isPipedInput
return cfg.CliOptions.Verbosity > 0 || isPipedInput
}

func generateSBOM(src *source.Source, errs chan error) (*sbom.SBOM, error) {
tasks, err := tasks()
func generateSBOM(src *source.Source, cfg *config.Application, errs chan error) (*sbom.SBOM, error) {
tasks, err := tasks(cfg)
if err != nil {
return nil, err
}
Expand All @@ -271,7 +274,7 @@ func generateSBOM(src *source.Source, errs chan error) (*sbom.SBOM, error) {
Descriptor: sbom.Descriptor{
Name: internal.ApplicationName,
Version: version.FromBuild().Version,
Configuration: appConfig,
Configuration: cfg,
},
}

Expand All @@ -291,12 +294,14 @@ func buildRelationships(s *sbom.SBOM, src *source.Source, tasks []task, errs cha
s.Relationships = append(s.Relationships, mergeRelationships(relationships...)...)
}

func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error {
func packagesExecWorker(si source.Input, cfg *config.Application, writer sbom.Writer) (chan *sbom.SBOM, <-chan error) {
errs := make(chan error)
outSbom := make(chan *sbom.SBOM, 1)

go func() {
defer close(errs)

src, cleanup, err := source.New(si, appConfig.Registry.ToOptions(), appConfig.Exclusions)
src, cleanup, err := source.New(si, cfg.Registry.ToOptions(), cfg.Exclusions)
if cleanup != nil {
defer cleanup()
}
Expand All @@ -305,7 +310,7 @@ func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error {
return
}

s, err := generateSBOM(src, errs)
s, err := generateSBOM(src, cfg, errs)
if err != nil {
errs <- err
return
Expand All @@ -315,8 +320,8 @@ func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error {
errs <- fmt.Errorf("no SBOM produced for %q", si.UserInput)
}

if appConfig.Anchore.Host != "" {
if err := runPackageSbomUpload(src, *s); err != nil {
if cfg.Anchore.Host != "" {
if err := runPackageSbomUpload(src, cfg, *s); err != nil {
errs <- err
return
}
Expand All @@ -326,8 +331,13 @@ func packagesExecWorker(si source.Input, writer sbom.Writer) <-chan error {
Type: event.Exit,
Value: func() error { return writer.Write(*s) },
})

if s != nil {
outSbom <- s
}
}()
return errs

return outSbom, errs
}

func mergeRelationships(cs ...<-chan artifact.Relationship) (relationships []artifact.Relationship) {
Expand All @@ -340,34 +350,34 @@ func mergeRelationships(cs ...<-chan artifact.Relationship) (relationships []art
return relationships
}

func runPackageSbomUpload(src *source.Source, s sbom.SBOM) error {
log.Infof("uploading results to %s", appConfig.Anchore.Host)
func runPackageSbomUpload(src *source.Source, cfg *config.Application, s sbom.SBOM) error {
log.Infof("uploading results to %s", cfg.Anchore.Host)

if src.Metadata.Scheme != source.ImageScheme {
return fmt.Errorf("unable to upload results: only images are supported")
}

var dockerfileContents []byte
if appConfig.Anchore.Dockerfile != "" {
if _, err := os.Stat(appConfig.Anchore.Dockerfile); os.IsNotExist(err) {
return fmt.Errorf("unable dockerfile=%q does not exist: %w", appConfig.Anchore.Dockerfile, err)
if cfg.Anchore.Dockerfile != "" {
if _, err := os.Stat(cfg.Anchore.Dockerfile); os.IsNotExist(err) {
return fmt.Errorf("unable dockerfile=%q does not exist: %w", cfg.Anchore.Dockerfile, err)
}

fh, err := os.Open(appConfig.Anchore.Dockerfile)
fh, err := os.Open(cfg.Anchore.Dockerfile)
if err != nil {
return fmt.Errorf("unable to open dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err)
return fmt.Errorf("unable to open dockerfile=%q: %w", cfg.Anchore.Dockerfile, err)
}

dockerfileContents, err = ioutil.ReadAll(fh)
if err != nil {
return fmt.Errorf("unable to read dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err)
return fmt.Errorf("unable to read dockerfile=%q: %w", cfg.Anchore.Dockerfile, err)
}
}

c, err := anchore.NewClient(anchore.Configuration{
BaseURL: appConfig.Anchore.Host,
Username: appConfig.Anchore.Username,
Password: appConfig.Anchore.Password,
BaseURL: cfg.Anchore.Host,
Username: cfg.Anchore.Username,
Password: cfg.Anchore.Password,
})
if err != nil {
return fmt.Errorf("failed to create anchore client: %w", err)
Expand All @@ -377,12 +387,12 @@ func runPackageSbomUpload(src *source.Source, s sbom.SBOM) error {
ImageMetadata: src.Image.Metadata,
SBOM: s,
Dockerfile: dockerfileContents,
OverwriteExistingUpload: appConfig.Anchore.OverwriteExistingImage,
Timeout: appConfig.Anchore.ImportTimeout,
OverwriteExistingUpload: cfg.Anchore.OverwriteExistingImage,
Timeout: cfg.Anchore.ImportTimeout,
}

if err := c.Import(context.Background(), importCfg); err != nil {
return fmt.Errorf("failed to upload results to host=%s: %+v", appConfig.Anchore.Host, err)
return fmt.Errorf("failed to upload results to host=%s: %+v", cfg.Anchore.Host, err)
}

return nil
Expand Down
Loading

0 comments on commit 5cf3da8

Please sign in to comment.