diff --git a/cli/docs/flags.go b/cli/docs/flags.go index 8f47c0a4..040cbbbf 100644 --- a/cli/docs/flags.go +++ b/cli/docs/flags.go @@ -87,6 +87,7 @@ const ( Watches = "watches" RepoPath = "repo-path" Licenses = "licenses" + UseTar = "tar" Fail = "fail" ExtendedTable = "extended-table" MinSeverity = "min-severity" @@ -121,7 +122,7 @@ var commandFlags = map[string][]string{ url, user, password, accessToken, ServerId, Project, Vuln, OutputFormat, Fail, ExtendedTable, Rescan, }, DockerScan: { - ServerId, Project, Watches, RepoPath, Licenses, OutputFormat, Fail, ExtendedTable, BypassArchiveLimits, MinSeverity, FixableOnly, + ServerId, Project, Watches, RepoPath, Licenses, UseTar, OutputFormat, Fail, ExtendedTable, BypassArchiveLimits, MinSeverity, FixableOnly, }, Audit: { url, user, password, accessToken, ServerId, InsecureTls, Project, Watches, RepoPath, Licenses, OutputFormat, ExcludeTestDeps, @@ -177,6 +178,7 @@ var flagsMap = map[string]components.Flag{ Watches: components.NewStringFlag(Watches, "A comma-separated list of Xray watches, to determine Xray's violations creation."), RepoPath: components.NewStringFlag(RepoPath, "Target repo path, to enable Xray to determine watches accordingly."), Licenses: components.NewBoolFlag(Licenses, "Set to true if you'd like to receive licenses from Xray scanning."), + UseTar: components.NewBoolFlag(UseTar, "Set to true to force request docker scan on a .tar file instead of an image."), OutputFormat: components.NewStringFlag( OutputFormat, "Defines the output format of the command. Acceptable values are: table, json, simple-json and sarif. Note: the json format doesn't include information about scans that are included as part of the Advanced Security package.", diff --git a/cli/scancommands.go b/cli/scancommands.go index dd1ac526..fd53ee7e 100644 --- a/cli/scancommands.go +++ b/cli/scancommands.go @@ -466,6 +466,7 @@ func DockerScan(c *components.Context, image string) error { SetProject(c.GetStringFlagValue(flags.Project)). SetIncludeVulnerabilities(shouldIncludeVulnerabilities(c)). SetIncludeLicenses(c.GetBoolFlagValue(flags.Licenses)). + SetIsTar(c.GetBoolFlagValue(flags.UseTar)). SetFail(c.GetBoolFlagValue(flags.Fail)). SetPrintExtendedTable(c.GetBoolFlagValue(flags.ExtendedTable)). SetBypassArchiveLimits(c.GetBoolFlagValue(flags.BypassArchiveLimits)). diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 4b9d5f4b..470dde30 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -24,6 +24,7 @@ type AuditCommand struct { IncludeLicenses bool Fail bool PrintExtendedTable bool + IsTar bool AuditParams } @@ -56,6 +57,11 @@ func (auditCmd *AuditCommand) SetIncludeLicenses(include bool) *AuditCommand { return auditCmd } +func (auditCmd *AuditCommand) SetIsTar(isTar bool) *AuditCommand { + auditCmd.IsTar = isTar + return auditCmd +} + func (auditCmd *AuditCommand) SetFail(fail bool) *AuditCommand { auditCmd.Fail = fail return auditCmd diff --git a/commands/scan/dockerscan.go b/commands/scan/dockerscan.go index 8e954792..be8eb090 100644 --- a/commands/scan/dockerscan.go +++ b/commands/scan/dockerscan.go @@ -3,16 +3,16 @@ package scan import ( "bytes" "fmt" + "os" + "os/exec" + "strings" + "github.com/jfrog/jfrog-cli-core/v2/common/spec" xrayutils "github.com/jfrog/jfrog-cli-security/utils" clientutils "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" - "os" - "os/exec" - "path/filepath" - "strings" ) const ( @@ -40,6 +40,11 @@ func (dsc *DockerScanCommand) SetTargetRepoPath(repoPath string) *DockerScanComm return dsc } +func (dsc *DockerScanCommand) SetIsTar(isTar bool) *DockerScanCommand { + dsc.isTar = isTar + return dsc +} + func (dsc *DockerScanCommand) Run() (err error) { // Validate Xray minimum version _, xrayVersion, err := xrayutils.CreateXrayServiceManagerAndGetVersion(dsc.ScanCommand.serverDetails) @@ -63,17 +68,20 @@ func (dsc *DockerScanCommand) Run() (err error) { }() // Run the 'docker save' command, to create tar file from the docker image, and pass it to the indexer-app - if dsc.progress != nil { - dsc.progress.SetHeadlineMsg("Creating image archive 📦") - } - log.Info("Creating image archive...") - imageTarPath := filepath.Join(tempDirPath, "image.tar") - dockerSaveCmd := exec.Command("docker", "save", dsc.imageTag, "-o", imageTarPath) - var stderr bytes.Buffer - dockerSaveCmd.Stderr = &stderr - err = dockerSaveCmd.Run() - if err != nil { - return fmt.Errorf("failed running command: '%s' with error: %s - %s", strings.Join(dockerSaveCmd.Args, " "), err.Error(), stderr.String()) + imageTarPath := dsc.imageTag + if !dsc.isTar { + skipSave := dsc.isTar || (fileutils.IsFileExists(dsc.imageTag) && strings.HasSuffix(".tar")) + if !skipSave { + dsc.progress.SetHeadlineMsg("Creating image archive 📦") + } + log.Info("Creating image archive...") + dockerSaveCmd := exec.Command("docker", "save", dsc.imageTag, "-o", imageTarPath) + var stderr bytes.Buffer + dockerSaveCmd.Stderr = &stderr + err = dockerSaveCmd.Run() + if err != nil { + return fmt.Errorf("failed running command: '%s' with error: %s - %s", strings.Join(dockerSaveCmd.Args, " "), err.Error(), stderr.String()) + } } // Perform scan on image.tar diff --git a/commands/scan/scan.go b/commands/scan/scan.go index b21e2ea5..b9f3eed1 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -57,6 +57,7 @@ type ScanCommand struct { printExtendedTable bool bypassArchiveLimits bool fixableOnly bool + isTar bool progress ioUtils.ProgressMgr } @@ -286,6 +287,11 @@ func (scanCmd *ScanCommand) CommandName() string { return "xr_scan" } +func (scanCmd *ScanCommand) SetIsTar(isTar bool) *ScanCommand { + scanCmd.isTar = isTar + return scanCmd +} + func (scanCmd *ScanCommand) prepareScanTasks(fileProducer, indexedFileProducer parallel.Runner, resultsArr [][]*services.ScanResponse, fileErrors, indexedFileErrors [][]formats.SimpleJsonError, fileCollectingErrorsQueue *clientutils.ErrorsQueue, xrayVersion string) { go func() { defer fileProducer.Done()