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

Feat/trivy #109

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
6 changes: 5 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ RUN apk add --no-cache \
unzip \
docker-cli \
aws-cli \
bash
bash \
docker

# Install Terraform
RUN curl -fsSL https://releases.hashicorp.com/terraform/1.5.7/terraform_1.5.7_linux_amd64.zip -o terraform.zip && \
unzip terraform.zip && \
mv terraform /usr/local/bin/ && \
rm terraform.zip

# Install Trivy (Vulnerability Scanner)
RUN curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin

# Set working directory
WORKDIR /go/src/app

Expand Down
16 changes: 4 additions & 12 deletions cmd/sdkr/provisionHub.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ Set DOCKER_USERNAME and DOCKER_PASSWORD environment variables for Docker Hub aut
}
pterm.Success.Println("Build completed successfully.")

pterm.Info.Println("Starting scan...")
scanErr := docker.Scout(fullImageName, configs.SarifFile)
pterm.Info.Println("Starting scan with Trivy...")
scanErr := docker.Trivy(fullImageName)
if scanErr != nil {
pterm.Error.Println("Scan failed:", scanErr)
} else {
Expand Down Expand Up @@ -158,7 +158,7 @@ Set DOCKER_USERNAME and DOCKER_PASSWORD environment variables for Docker Hub aut
# Provide "myuser/myimage:latest" as an argument
smurf sdkr provision-hub myuser/myimage:latest --context . --file Dockerfile --no-cache \
--build-arg key1=value1 --build-arg key2=value2 --target my-target --platform linux/amd64 \
--output myscan.sarif --yes --delete
--yes --delete

# If you omit the argument, it will read from config and rely on "image_name" from there
smurf sdkr provision-hub --yes --delete
Expand Down Expand Up @@ -208,14 +208,6 @@ func init() {
"",
"Build context directory (default: current directory)",
)

provisionHubCmd.Flags().StringVarP(
&configs.SarifFile,
"output", "o",
"",
"Output file for SARIF report",
)

provisionHubCmd.Flags().BoolVarP(
&configs.ConfirmAfterPush,
"yes", "y",
Expand All @@ -230,4 +222,4 @@ func init() {
)

sdkrCmd.AddCommand(provisionHubCmd)
}
}
85 changes: 40 additions & 45 deletions cmd/sdkr/scan.go
Original file line number Diff line number Diff line change
@@ -1,58 +1,53 @@
package sdkr

import (
"errors"
"fmt"

"github.com/clouddrove/smurf/configs"
"github.com/clouddrove/smurf/internal/docker"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
"errors"
"fmt"
"github.com/clouddrove/smurf/configs"
"github.com/clouddrove/smurf/internal/docker"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
)

// scanCmd provides functionality to scan a Docker image for known security issues.
// It supports both direct command-line arguments and configuration file values for the image name,
// and optionally allows saving the scan report to a specified SARIF file.
var scanCmd = &cobra.Command{
Use: "scan [IMAGE_NAME[:TAG]]",
Short: "Scan a Docker image for known vulnerabilities.",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
var imageRef string

if len(args) == 1 {
imageRef = args[0]
} else {
data, err := configs.LoadConfig(configs.FileName)
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
if data.Sdkr.ImageName == "" {
return errors.New("image name (with optional tag) must be provided either as an argument or in the config")
}
imageRef = data.Sdkr.ImageName
}

pterm.Info.Printf("Scanning Docker image %q...\n", imageRef)
err := docker.Scout(imageRef, configs.SarifFile)
if err != nil {
pterm.Error.Println("Scan failed:", err)
return err
}
pterm.Success.Println("Scan completed successfully.")
return nil
},
Example: `
smurf sdkr scan my-image:latest
smurf sdkr scan
# In the second example, it will read IMAGE_NAME from the config file

smurf sdkr scan my-image:latest --output scan.json
# Saves the scan report to 'scan.json' in SARIF format
Use: "scan [IMAGE_NAME[:TAG]]",
Short: "Scan a Docker image for known vulnerabilities.",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
var imageRef string
if len(args) == 1 {
imageRef = args[0]
} else {
data, err := configs.LoadConfig(configs.FileName)
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
if data.Sdkr.ImageName == "" {
return errors.New("image name (with optional tag) must be provided either as an argument or in the config")
}
imageRef = data.Sdkr.ImageName
}

pterm.Info.Printf("Scanning Docker image %q...\n", imageRef)
err := docker.Trivy(imageRef)
if err != nil {
pterm.Error.Println("Scan failed:", err)
return err
}

pterm.Success.Println("Scan completed successfully.")
return nil
},
Example: `
smurf sdkr scan my-image:latest
smurf sdkr scan
# In the second example, it will read IMAGE_NAME from the config file
`,
}

func init() {
scanCmd.Flags().StringVarP(&configs.SarifFile, "output", "o", "", "Output file for SARIF report")
sdkrCmd.AddCommand(scanCmd)
}
sdkrCmd.AddCommand(scanCmd)
}
9 changes: 7 additions & 2 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ if [[ -n "$DOCKER_USERNAME" && -n "$DOCKER_PASSWORD" ]]; then
echo "✅ Successfully logged into Docker Hub."
fi

# Perform AWS and EKS login
aws_eks_login
# Perform AWS and EKS login only if AWS_AUTH=true
if [[ "$AWS_AUTH" == "true" ]]; then
echo "🔹 AWS authentication is enabled. Performing AWS login..."
aws_eks_login
else
echo "⚠️ AWS authentication is disabled. Skipping AWS login."
fi

# Initialize command with base command
SMURF_CMD="/usr/local/bin/smurf"
Expand Down
52 changes: 17 additions & 35 deletions internal/docker/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,44 @@ import (
"bytes"
"context"
"fmt"
"os"
"os/exec"

"github.com/fatih/color"
"github.com/pterm/pterm"
)

// Scout runs 'docker scout cves' to scan a Docker image for vulnerabilities
// and optionally saves the results to a SARIF file.
// It displays the output of the scan and prints a success message upon completion.
func Scout(dockerTag, sarifFile string) error {
// Trivy runs 'trivy image' to scan a Docker image for vulnerabilities
// and displays the results. It's a simplified version that accepts just the image name and tag.
func Trivy(dockerImage string) error {
ctx := context.Background()

args := []string{"scout", "cves", dockerTag}

if sarifFile != "" {
args = append(args, "--output", sarifFile)
}

cmd := exec.CommandContext(ctx, "docker", args...)

args := []string{"image", dockerImage, "--format", "table"}

cmd := exec.CommandContext(ctx, "trivy", args...)
var stdoutBuf, stderrBuf bytes.Buffer
cmd.Stdout = &stdoutBuf
cmd.Stderr = &stderrBuf

spinner, _ := pterm.DefaultSpinner.Start("Running 'docker scout cves'")
spinner, _ := pterm.DefaultSpinner.Start("Running 'trivy image' scan")
defer spinner.Stop()

err := cmd.Run()

spinner.Stop()

outStr := stdoutBuf.String()
errStr := stderrBuf.String()

if err != nil {
pterm.Error.Println("Error running 'docker scout cves':", err)
pterm.Error.Println("Error running 'trivy image':", err)
if errStr != "" {
pterm.Error.Println(errStr)
}
return fmt.Errorf("failed to run 'docker scout cves': %w", err)
return fmt.Errorf("failed to run 'trivy image': %w", err)
}

if outStr != "" {
pterm.Info.Println("Docker Scout CVEs output:")
pterm.Info.Println("Trivy scan results:")
fmt.Println(color.YellowString(outStr))
}

if sarifFile != "" {
if _, err := os.Stat(sarifFile); err == nil {
pterm.Success.Println("SARIF report saved to:", sarifFile)
} else {
pterm.Warning.Println("Expected SARIF report not found at:", sarifFile)
}
}


pterm.Success.Println("Scan completed successfully.")
return nil
}
}