From 5caebcc9f3b38964d044c5a64b417b04cfb3fe73 Mon Sep 17 00:00:00 2001 From: Christian Kotzbauer Date: Fri, 21 Jan 2022 08:07:05 +0100 Subject: [PATCH] feat: add configurable sbom-format close #4 Signed-off-by: Christian Kotzbauer --- README.md | 1 + internal/daemon/daemon.go | 13 ++++++--- internal/syft/syft.go | 60 +++++++++++++++++++++++++++++++-------- main.go | 1 + 4 files changed, 59 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c9efd099..3dcfbcc1 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ All parameters are cli-flags. |-----------|----------|---------|-------------| | `verbosity` | `false` | `info` | Log-level (debug, info, warn, error, fatal, panic) | | `cron` | `false` | `@hourly` | Backround-Service interval (CRON). All options from [github.com/robfig/cron](github.com/robfig/cron) are allowed | +| `format` | `false` | `json` | SBOM-Format. | | `git-workingtree` | `false` | `/work` | Directory to place the git-repo. | | `git-repository` | `true` | `""` | Git-Repository-URL (HTTPS). | | `git-branch` | `false` | `main` | Git-Branch to checkout. | diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index e0ce12da..1036f24f 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -46,6 +46,7 @@ func (c *CronService) runBackgroundService() { logrus.Info("Execute background-service") workingTree := viper.GetString("git-workingtree") gitPath := viper.GetString("git-path") + format := viper.GetString("format") workPath := path.Join(workingTree, gitPath) gitAccount := git.New(viper.GetString("git-access-token"), viper.GetString("git-author-name"), viper.GetString("git-author-email")) @@ -57,13 +58,15 @@ func (c *CronService) runBackgroundService() { processedSbomFiles := []string{} + sy := syft.New(workingTree, gitPath, format) + for _, ns := range namespaces { pods := client.ListPods(ns.Name, viper.GetString("pod-label-selector")) logrus.Debugf("Discovered %v pods in namespace %v", len(pods), ns.Name) digests := client.GetContainerDigests(pods) for _, d := range digests { - sbomPath := syft.ExecuteSyft(d, workingTree, gitPath) + sbomPath := sy.ExecuteSyft(d) processedSbomFiles = append(processedSbomFiles, sbomPath) } @@ -72,7 +75,9 @@ func (c *CronService) runBackgroundService() { logrus.Debug("Start to remove old SBOMs") ignoreDirs := []string{".git"} - err := filepath.Walk(workPath, deleteObsoleteFiles(workingTree, ignoreDirs, processedSbomFiles, gitAccount)) + fileName := syft.GetFileName(format) + + err := filepath.Walk(workPath, deleteObsoleteFiles(workingTree, fileName, ignoreDirs, processedSbomFiles, gitAccount)) if err != nil { logrus.WithError(err).Error("Could not cleanup old SBOMs") } else { @@ -82,7 +87,7 @@ func (c *CronService) runBackgroundService() { c.printNextExecution() } -func deleteObsoleteFiles(workPath string, ignoreDirs, processedSbomFiles []string, gitAccount git.GitAccount) filepath.WalkFunc { +func deleteObsoleteFiles(workPath, fileName string, ignoreDirs, processedSbomFiles []string, gitAccount git.GitAccount) filepath.WalkFunc { return func(p string, info os.FileInfo, err error) error { if err != nil { logrus.WithError(err).Errorf("An error occurred while processing %s", p) @@ -98,7 +103,7 @@ func deleteObsoleteFiles(workPath string, ignoreDirs, processedSbomFiles []strin } } - if info.Name() == "sbom.json" { + if info.Name() == fileName { found := false for _, f := range processedSbomFiles { if f == p { diff --git a/internal/syft/syft.go b/internal/syft/syft.go index 9594c145..4d5b9342 100644 --- a/internal/syft/syft.go +++ b/internal/syft/syft.go @@ -14,13 +14,28 @@ import ( "github.com/sirupsen/logrus" ) -func ExecuteSyft(img kubernetes.ImageDigest, gitWorkingTree, gitPath string) string { - name := strings.ReplaceAll(img.Digest, "@", "/") - name = strings.ReplaceAll(path.Join(gitWorkingTree, gitPath, name, "sbom.json"), ":", "_") +type Syft struct { + GitWorkingTree string + GitPath string + SbomFormat string +} + +func New(gitWorkingTree, gitPath, sbomFormat string) Syft { + return Syft{ + GitWorkingTree: gitWorkingTree, + GitPath: gitPath, + SbomFormat: sbomFormat, + } +} - if pathExists(name) { +func (s *Syft) ExecuteSyft(img kubernetes.ImageDigest) string { + fileName := GetFileName(s.SbomFormat) + filePath := strings.ReplaceAll(img.Digest, "@", "/") + filePath = strings.ReplaceAll(path.Join(s.GitWorkingTree, s.GitPath, filePath, fileName), ":", "_") + + if pathExists(filePath) { logrus.Debugf("Skip image %s", img.Digest) - return name + return filePath } logrus.Debugf("Processing image %s", img.Digest) @@ -33,10 +48,10 @@ func ExecuteSyft(img kubernetes.ImageDigest, gitWorkingTree, gitPath string) str if err != nil { logrus.WithError(err).Error("Image-Pull failed") - return name + return filePath } - cmd := exec.Command("syft", imagePath, "-o", "json") + cmd := exec.Command("syft", imagePath, "-o", s.SbomFormat) var errb bytes.Buffer cmd.Stderr = &errb stdout, err := cmd.Output() @@ -45,25 +60,46 @@ func ExecuteSyft(img kubernetes.ImageDigest, gitWorkingTree, gitPath string) str if err != nil { logrus.WithError(err).WithField("stderr", errb.String()).Error("Syft stopped with error") - return name + return filePath } - dir := filepath.Dir(name) + dir := filepath.Dir(filePath) err = os.MkdirAll(dir, 0777) if err != nil { logrus.WithError(err).Error("Directory could not be created") - return name + return filePath } data := []byte(stdout) - err = os.WriteFile(name, data, 0640) + err = os.WriteFile(filePath, data, 0640) if err != nil { logrus.WithError(err).Error("SBOM could not be saved") } - return name + return filePath +} + +func GetFileName(sbomFormat string) string { + switch sbomFormat { + case "json": + return "sbom.json" + case "text": + return "sbom.txt" + case "cyclonedx": + return "sbom.xml" + case "cyclonedx-json": + return "sbom.json" + case "spdx": + return "sbom.spdx" + case "spdx-json": + return "sbom.json" + case "table": + return "sbom.txt" + default: + return "sbom.json" + } } func pathExists(path string) bool { diff --git a/main.go b/main.go index 59e4f2e0..05ff6502 100644 --- a/main.go +++ b/main.go @@ -45,6 +45,7 @@ func init() { rootCmd.PersistentFlags().StringVarP(&verbosity, "verbosity", "v", logrus.InfoLevel.String(), "Log-level (debug, info, warn, error, fatal, panic)") rootCmd.PersistentFlags().StringVarP(&daemonCron, "cron", "c", "@hourly", "Backround-Service interval (CRON)") + rootCmd.PersistentFlags().String("format", "json", "SBOM-Format.") rootCmd.PersistentFlags().String("git-workingtree", "/work", "Directory to place the git-repo.") rootCmd.PersistentFlags().String("git-repository", "", "Git-Repository-URL (HTTPS).") rootCmd.PersistentFlags().String("git-branch", "main", "Git-Branch to checkout.")