Skip to content

Commit

Permalink
feat: add cve counts to md report
Browse files Browse the repository at this point in the history
  • Loading branch information
mhrabovcin committed Feb 20, 2024
1 parent e5fe069 commit a9e9608
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 19 deletions.
10 changes: 6 additions & 4 deletions .github/actions/copacetic-action/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ inputs:
description: 'List of images to process separated by newline'
required: true
type: string
# buildkit-version:
# description: 'Buildkit version'
# type: string
skip-upload:
description: 'Skip uploading to remote registry'
default: false
Expand All @@ -27,6 +24,11 @@ inputs:
default: 1h
required: false
type: string
report-cves:
description: 'Scan and report number of Critical and Highs'
default: false
required: false
type: boolean
outputs:
result:
description: "Patching result"
Expand Down Expand Up @@ -83,7 +85,7 @@ runs:
run: |
JSON_REPORT_PATH=$(mktemp)
echo "$JSON_REPORT" > $JSON_REPORT_PATH
RESULT="$(devbox run -- go run main.go markdown $JSON_REPORT_PATH)"
RESULT="$(devbox run -- go run main.go markdown $JSON_REPORT_PATH) --print-cves=${{ inputs.report-cves }}"
echo "$RESULT" >> $GITHUB_STEP_SUMMARY
env:
JSON_REPORT: ${{ steps.execute-patch.outputs.result }}
Expand Down
7 changes: 5 additions & 2 deletions .github/actions/copacetic-action/cmd/copa-action/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import (
"github.com/spf13/cobra"
)

var printCVEs = false

func NewMarkdownCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "markdown PATH | -",
Short: "Generate markdown report from JSON output",
Args: cobra.ExactArgs(1),
RunE: func(_ *cobra.Command, args []string) error {
RunE: func(cmd *cobra.Command, args []string) error {
input, err := cli.OpenFileOrStdin(args[0])
if err != nil {
return err
Expand All @@ -31,8 +33,9 @@ func NewMarkdownCmd() *cobra.Command {
return fmt.Errorf("failed to read JSON report: %w", err)
}

return patch.WriteMarkdown(report, os.Stdout)
return patch.WriteMarkdown(cmd.Context(), report, os.Stdout, printCVEs)
},
}
cmd.Flags().BoolVar(&printCVEs, "print-cves", printCVEs, "enable scanning and printing number of Critical and High CVEs")
return cmd
}
11 changes: 9 additions & 2 deletions .github/actions/copacetic-action/pkg/image/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,17 @@ func (e *CmdErr) Error() string {
return e.Err.Error()
}

var (
ScanFixableOS = []string{"--vuln-type", "os", "--ignore-unfixed"}
ScanAllOS = []string{"--vuln-type", "os"}
)

// Scan runs a trivy scan of a image and returns back report.
func Scan(ctx context.Context, imageName string) (*Report, error) {
func Scan(ctx context.Context, imageName string, scanType []string) (*Report, error) {
flags := append([]string{"image"}, scanType...)
flags = append(flags, "--format", "json", imageName)
cmd, stdout, stderr := prepareCmd(
ctx, "trivy", "image", "--vuln-type", "os", "--ignore-unfixed", "--format", "json", imageName,
ctx, "trivy", flags...,
)
err := cmd.Run()
if err != nil {
Expand Down
31 changes: 30 additions & 1 deletion .github/actions/copacetic-action/pkg/patch/report.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package patch

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -44,7 +45,7 @@ func WriteJSON(tasks []*Task, w io.Writer) error {
return json.NewEncoder(w).Encode(r)
}

func WriteMarkdown(report Report, w io.Writer) error {
func WriteMarkdown(ctx context.Context, report Report, w io.Writer, printCVEs bool) error {
doc := md.NewMarkdown(w)

imagesTable := md.TableSet{
Expand All @@ -59,6 +60,11 @@ func WriteMarkdown(report Report, w io.Writer) error {
md.Code(row.Patched),
}

if printCVEs {
mdRow[0] = fmt.Sprintf("%s<br/>%s", row.Image, scanImage(ctx, row.Image))
mdRow[1] = fmt.Sprintf("%s<br/>%s", row.Patched, scanImage(ctx, row.Patched))
}

if row.Error != "" {
mdRow = append(mdRow, md.Link("View error", fmt.Sprintf("#error-%d", i)))

Expand Down Expand Up @@ -96,3 +102,26 @@ func WriteMarkdown(report Report, w io.Writer) error {

return doc.Build()
}

func scanImage(ctx context.Context, imageRef string) string {
report, err := image.Scan(ctx, imageRef, image.ScanAllOS)
if err != nil {
return md.Code(err.Error())
}

counts := map[string]int{
"CRITICAL": 0,
"HIGH": 0,
}
for _, vuln := range report.Vulnerabilities() {
if _, ok := counts[vuln.Severity]; ok {
counts[vuln.Severity] = counts[vuln.Severity] + 1
}
}

parts := []string{}
for severity, count := range counts {
parts = append(parts, fmt.Sprintf("`%d` %s", count, md.Bold(severity)))
}
return strings.Join(parts, " ")
}
12 changes: 4 additions & 8 deletions .github/actions/copacetic-action/pkg/patch/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func Run(ctx context.Context, imageRef string, reg registry.Registry, imageTagSu
// To avoid generating same patched image always scan the latest patched
// tag in the patch registry and only build image if there are available
// fixes that would change the latest patched version.
report, err := image.Scan(ctx, imagePatch.Scanned)
report, err := image.Scan(ctx, imagePatch.Scanned, image.ScanFixableOS)
if err != nil {
return withErr(t, err), err
}
Expand Down Expand Up @@ -96,21 +96,17 @@ func Run(ctx context.Context, imageRef string, reg registry.Registry, imageTagSu
patchedRef := imagePatch.SourceRef().Context().Tag(buildTag)
logger.Info("regenerated image using copa", "patchedRef", patchedRef.String())

patchedReport, err := image.Scan(ctx, patchedRef.String())
patchedReport, err := image.Scan(ctx, patchedRef.String(), image.ScanFixableOS)
if err != nil {
return withErr(t, err), err
}
logger.Info(
"patched vulnerability report",
"original", report.Vulnerabilities(),
"patched", patchedReport.Vulnerabilities(),
)

if slices.Equal(
image.VulnerabilitiesIdsSorted(report.Vulnerabilities()),
image.VulnerabilitiesIdsSorted(patchedReport.Vulnerabilities()),
) {
logger.Warn("no vulnerabilties were fixed by running copa",
logger.Warn(
"no vulnerabilties were fixed by running copa patch",
"scannedImage", imagePatch.Scanned,
"scanned", image.VulnerabilitiesIdsSorted(report.Vulnerabilities()),
"patched", image.VulnerabilitiesIdsSorted(patchedReport.Vulnerabilities()),
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/cve-patch-images.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ jobs:
with:
images: ${{ steps.save-images.outputs.images }}
github-token: ${{ secrets.GITHUB_TOKEN }}
debug: true
skip-upload: true
timeout: 2h
report-cves: true

0 comments on commit a9e9608

Please sign in to comment.