Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aggregate code scanning sarifs from command summaries #2683

Merged
merged 5 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 66 additions & 14 deletions general/summary/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ const (
)

const (
JfrogCliSummaryDir = "jfrog-command-summary"
MarkdownFileName = "markdown.md"
markdownFileName = "markdown.md"
finalSarifFileName = "final.sarif"
)

var markdownSections = []MarkdownSection{Security, BuildInfo, Upload}
Expand All @@ -37,13 +37,22 @@ func (ms MarkdownSection) String() string {
return string(ms)
}

// GenerateSummaryMarkdown creates a summary of recorded CLI commands in Markdown format.
func GenerateSummaryMarkdown(c *cli.Context) error {
// Generates a combined markdown from all sections, and aggregates multiple SARIF files into one.
func FinalizeCommandSummaries(c *cli.Context) error {
RobiNino marked this conversation as resolved.
Show resolved Hide resolved
if !shouldGenerateSummary() {
return fmt.Errorf("unable to generate the command summary because the output directory is not specified."+
" Please ensure that the environment variable '%s' is set before running your commands to enable summary generation", coreutils.SummaryOutputDirPathEnv)
}

if err := generateSummaryMarkdown(c); err != nil {
return err
}

return aggregatedCodeScanningSarifs()
}

// generateSummaryMarkdown creates a summary of recorded CLI commands in Markdown format.
func generateSummaryMarkdown(c *cli.Context) error {
// Get URL and Version to generate summary links
serverUrl, majorVersion, err := extractServerUrlAndVersion(c)
if err != nil {
Expand Down Expand Up @@ -71,6 +80,26 @@ func GenerateSummaryMarkdown(c *cli.Context) error {
return saveMarkdownToFileSystem(finalMarkdown)
}

func aggregatedCodeScanningSarifs() error {
files, err := getSarifFiles()
RobiNino marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
if len(files) == 0 {
log.Debug("No sarif reports were found")
return nil
}
finalSarif, err := securityUtils.CombineSarifOutputFiles(files)
if err != nil {
return err
}
return saveFinalSarifToFileSystem(string(finalSarif))
}

func getSarifReportsDir() string {
return filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), commandsummary.OutputDirName, string(Security), string(commandsummary.SarifReport))
}

// The CLI generates summaries in sections, with each section as a separate Markdown file.
// This function merges all sections into a single Markdown file and saves it in the root of the
// command summary output directory.
Expand All @@ -93,23 +122,29 @@ func saveMarkdownToFileSystem(finalMarkdown string) (err error) {
if finalMarkdown == "" {
return nil
}
filePath := filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), JfrogCliSummaryDir, MarkdownFileName)
filePath := filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), commandsummary.OutputDirName, markdownFileName)
return saveFile(finalMarkdown, filePath)
}

func saveFile(content, filePath string) (err error) {
if content == "" {
return nil
}
file, err := os.Create(filePath)
if err != nil {
return fmt.Errorf("error creating markdown file: %w", err)
return err
}
defer func() {
err = errors.Join(err, file.Close())
}()
// Write to file
if _, err := file.WriteString(finalMarkdown); err != nil {
return fmt.Errorf("error writing to markdown file: %w", err)
if _, err = file.WriteString(content); err != nil {
return err
}
return nil
}

func getSectionMarkdownContent(section MarkdownSection) (string, error) {
sectionFilepath := filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), JfrogCliSummaryDir, string(section), MarkdownFileName)
sectionFilepath := filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), commandsummary.OutputDirName, string(section), markdownFileName)
if _, err := os.Stat(sectionFilepath); os.IsNotExist(err) {
return "", nil
}
Expand All @@ -124,6 +159,23 @@ func getSectionMarkdownContent(section MarkdownSection) (string, error) {
return string(contentBytes), nil
}

func getSarifFiles() (files []string, err error) {
indexedFiles, err := commandsummary.GetIndexedDataFilesPaths()
if err != nil {
return
}
sarifsMap := indexedFiles[commandsummary.SarifReport]
for i := range sarifsMap {
files = append(files, sarifsMap[i])
}
return
}

func saveFinalSarifToFileSystem(finalSarif string) (err error) {
filePath := filepath.Join(getSarifReportsDir(), finalSarifFileName)
return saveFile(finalSarif, filePath)
}

// Initiate the desired command summary implementation and invoke its Markdown generation.
func invokeSectionMarkdownGeneration(section MarkdownSection) error {
switch section {
Expand Down Expand Up @@ -151,7 +203,7 @@ func generateBuildInfoMarkdown() error {
if err != nil {
return fmt.Errorf("error generating build-info markdown: %w", err)
}
if err = mapScanResults(buildInfoSummary); err != nil {
if err = mapScanResults(); err != nil {
return fmt.Errorf("error mapping scan results: %w", err)
}
return buildInfoSummary.GenerateMarkdown()
Expand All @@ -170,9 +222,9 @@ func generateUploadMarkdown() error {
}

// mapScanResults maps the scan results saved during runtime into scan components.
func mapScanResults(commandSummary *commandsummary.CommandSummary) (err error) {
func mapScanResults() (err error) {
// Gets the saved scan results file paths.
indexedFiles, err := commandSummary.GetIndexedDataFilesPaths()
indexedFiles, err := commandsummary.GetIndexedDataFilesPaths()
if err != nil {
return err
}
Expand Down Expand Up @@ -216,7 +268,7 @@ func processScan(index commandsummary.Index, filePath string, scannedName string

// shouldGenerateUploadSummary checks if upload summary should be generated.
func shouldGenerateUploadSummary() (bool, error) {
buildInfoPath := filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), JfrogCliSummaryDir, string(BuildInfo))
buildInfoPath := filepath.Join(os.Getenv(coreutils.SummaryOutputDirPathEnv), commandsummary.OutputDirName, string(BuildInfo))
if _, err := os.Stat(buildInfoPath); os.IsNotExist(err) {
return true, nil
}
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ require (
github.com/jfrog/build-info-go v1.9.35
github.com/jfrog/gofrog v1.7.5
github.com/jfrog/jfrog-cli-artifactory v0.1.6
github.com/jfrog/jfrog-cli-core/v2 v2.55.6
github.com/jfrog/jfrog-cli-core/v2 v2.55.7
github.com/jfrog/jfrog-cli-platform-services v1.3.0
github.com/jfrog/jfrog-cli-security v1.7.2
github.com/jfrog/jfrog-cli-security v1.8.0
github.com/jfrog/jfrog-client-go v1.46.1
github.com/jszwec/csvutil v1.10.0
github.com/stretchr/testify v1.9.0
Expand Down Expand Up @@ -171,9 +171,9 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)

// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/eyaldelarea/jfrog-cli-core/v2 v2.0.0-20240829171158-7b0f89df2c0c
// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/RobiNino/jfrog-cli-core/v2 v2.0.0-20240904105726-775a1614224e

// replace github.com/jfrog/jfrog-cli-security => github.com/attiasas/jfrog-cli-security v0.0.0-20240829151632-3a7a90969eca
// replace github.com/jfrog/jfrog-cli-security => github.com/attiasas/jfrog-cli-security v0.0.0-20240904061406-f368939ce3a0

// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240806162439-01bb7dcd43fc

Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -941,12 +941,12 @@ github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYL
github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w=
github.com/jfrog/jfrog-cli-artifactory v0.1.6 h1:bMfJsrLQJw0dZp4nqUf1xOmtY0rpCatW/I5q88x+fhQ=
github.com/jfrog/jfrog-cli-artifactory v0.1.6/go.mod h1:jbNb22ebtupcjdhrdGq0VBew2vWG6VUK04xxGNDfynE=
github.com/jfrog/jfrog-cli-core/v2 v2.55.6 h1:3tQuEdYgS2q7fkrrSG66OnO0S998FXGaY9BVsxSLst4=
github.com/jfrog/jfrog-cli-core/v2 v2.55.6/go.mod h1:DPO5BfWAeOByahFMMy+PcjmbPlcyoRy7Bf2C5sGKVi0=
github.com/jfrog/jfrog-cli-core/v2 v2.55.7 h1:V4dO2FMNIH49lov3dMj3jYRg8KBTG7hyhHI8ftYByf8=
github.com/jfrog/jfrog-cli-core/v2 v2.55.7/go.mod h1:DPO5BfWAeOByahFMMy+PcjmbPlcyoRy7Bf2C5sGKVi0=
github.com/jfrog/jfrog-cli-platform-services v1.3.0 h1:IblSDZFBjL7WLRi37Ni2DmHrXJJ6ysSMxx7t41AvyDA=
github.com/jfrog/jfrog-cli-platform-services v1.3.0/go.mod h1:Ky4SDXuMeaiNP/5zMT1YSzIuXG+cNYYOl8BaEA7Awbc=
github.com/jfrog/jfrog-cli-security v1.7.2 h1:Kvabj/6LhM+WEb6woIqqbv2VmIj69IFwz859Sys1Tgs=
github.com/jfrog/jfrog-cli-security v1.7.2/go.mod h1:4eztJ+gBb7Xtq/TtnOvIodBOMZutPIAZOuLxqHWXrOo=
github.com/jfrog/jfrog-cli-security v1.8.0 h1:jp/AVaQcItUNXRCud5PMyl8VVjPuzfrNHJWQvWAMnms=
github.com/jfrog/jfrog-cli-security v1.8.0/go.mod h1:DjufYZpsTwILOFJlx7tR/y63oLBRmtPtFIz1WgiP/X4=
github.com/jfrog/jfrog-client-go v1.46.1 h1:ExqOF8ClOG9LO3vbm6jTIwQHHhprbu8lxB2RrM6mMI0=
github.com/jfrog/jfrog-client-go v1.46.1/go.mod h1:UCu2JNBfMp9rypEmCL84DCooG79xWIHVadZQR3Ab+BQ=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ func getCommands() ([]cli.Command, error) {
Usage: summaryDocs.GetDescription(),
HelpName: corecommon.CreateUsage("gsm", summaryDocs.GetDescription(), summaryDocs.Usage),
Category: otherCategory,
Action: summary.GenerateSummaryMarkdown,
Action: summary.FinalizeCommandSummaries,
},
}

Expand Down
1 change: 1 addition & 0 deletions transfer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ func generateTestRepoSnapshotFile(t *testing.T, repoKey, repoSnapshotFilePath st
func addChildWithFiles(t *testing.T, parent *reposnapshot.Node, dirName string, explored, checkCompleted bool, filesCount int) *reposnapshot.Node {
childNode := reposnapshot.CreateNewNode(dirName, nil)
for i := 0; i < filesCount; i++ {
//#nosec G115
assert.NoError(t, childNode.IncrementFilesCount(uint64(i)))
}

Expand Down
Loading