Skip to content

Commit

Permalink
added logging for git context. Added config files for running portage…
Browse files Browse the repository at this point in the history
… on gatecheck. (#5)

---------

Co-authored-by: Aaron Yee <[email protected]>
  • Loading branch information
Relu808 and ayee808 authored Jan 31, 2025
1 parent 944140a commit d34dba6
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 30 deletions.
107 changes: 107 additions & 0 deletions .custom-gatecheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
version: "1"

metadata:
tags: [] # Additional metadata tags for the configuration

# Grype scanner configuration (for container/dependency vulnerability scanning)
grype:
# Maximum allowed vulnerabilities by severity level
severityLimit:
critical:
enabled: false # Whether to enforce critical severity limits
limit: 0 # Maximum number of critical vulnerabilities allowed
high:
enabled: false
limit: 7
medium:
enabled: false
limit: 0
low:
enabled: false
limit: 0

epssLimit:
enabled: false # Whether to enforce EPSS (Exploit Prediction Scoring System) limits
score: 0 # Maximum allowed EPSS score

kevLimitEnabled: false # Whether to enforce Known Exploited Vulnerabilities (KEV) limits

cveLimit:
enabled: false # Whether to enforce specific CVE limits
cves: [] # List of specific CVEs to check against

epssRiskAcceptance:
enabled: false # Whether to accept risks based on EPSS scores
score: 0.001 # EPSS score threshold for risk acceptance

cveRiskAcceptance:
enabled: false # Whether to accept risks for specific CVEs
cves: [] # List of accepted CVEs

# CycloneDX configuration (for Software Bill of Materials scanning)
cyclonedx:
# Similar structure to grype configuration
# Controls vulnerability limits and risk acceptance for SBOM analysis
severityLimit:
critical:
enabled: false
limit: 0
high:
enabled: false
limit: 0
medium:
enabled: false
limit: 0
low:
enabled: false
limit: 0
epssLimit:
enabled: false
score: 0
kevLimitEnabled: false
cveLimit:
enabled: false
cves: []
epssRiskAcceptance:
enabled: false
score: 0
cveRiskAcceptance:
enabled: false
cves: []

# Semgrep configuration (for static code analysis)
semgrep:
# Maximum allowed findings by severity level
severityLimit:
error:
enabled: false
limit: 5 # Maximum number of error-level findings allowed
warning:
enabled: false
limit: 0
info:
enabled: false
limit: 0

# Risk acceptance configuration based on impact levels
impactRiskAcceptance:
enabled: true # Whether to use impact-based risk acceptance
high: false # Whether to accept high-impact findings
medium: false # Whether to accept medium-impact findings
low: true # Whether to accept low-impact findings

# Gitleaks configuration (for secrets scanning)
gitleaks:
limitEnabled: false # Whether to enforce limits on secrets findings

# Code coverage requirements
coverage:
lineThreshold: 0 # Minimum required line coverage percentage
functionThreshold: 0 # Minimum required function coverage percentage
branchThreshold: 0 # Minimum required branch coverage percentage

# API configuration for submitting results
api:
enabled: true # Whether to submit results to API
endpoint: http://localhost:5168/Build/SubmitArtifacts # API endpoint for submitting results
skipVerify: true # Whether to skip SSL verification
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ bin/
dist/
book/
cover.cov
artifacts/
.env.local
50 changes: 50 additions & 0 deletions .portage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Base Configuration
version: "1"
imageTag: "ghcr.io/easy-up/gatecheck:latest" # The full image tag for the target container image (e.g. my-org/my-app:latest)
artifactDir: "artifacts" # Directory for generated artifacts (e.g. ./artifacts)
gatecheckBundleFilename: "gatecheck-bundle.tar.gz" # Filename for the gatecheck bundle (e.g. gatecheck-bundle.tar.gz)

# Image Build Configuration
imageBuild:
enabled: false # Enable/Disable the image build pipeline (true/false)
buildDir: "." # Build directory for image (e.g. ./cmd/portage)
dockerfile: "Dockerfile" # Dockerfile to use (e.g. ./cmd/portage/Dockerfile)
platform: "" # Target platform (e.g. linux/amd64, linux/arm64)
target: "" # Target stage for multi-stage builds (e.g. build, test, publish)
cacheTo: "" # Cache export location (e.g. type=local,dest=path)
cacheFrom: "" # Cache import location (e.g. type=local,src=path)
squashLayers: false # Whether to squash layers (true/false)
args: {} # Build arguments (e.g. BUILD_ARGS=--build-arg=key=value)

# Image Scan Configuration
imageScan:
enabled: false # Enable/Disable the image scan pipeline (true/false)
syftFilename: "syft-sbom-report.json" # Filename for the syft sbom report (e.g. syft-sbom-report.json)
grypeConfigFilename: "" # Filename for the grype config (e.g. grype-config.json)
grypeFilename: "grype-vulnerability-report-full.json" # Filename for the grype vulnerability report (e.g. grype-vulnerability-report-full.json)
clamavFilename: "clamav-virus-report.txt" # Filename for the clamav virus report (e.g. clamav-virus-report.txt)

# Code Scan Configuration
codeScan:
enabled: true # Enable/Disable the code scan pipeline (true/false)
gitleaksFilename: "gitleaks-secrets-report.json"
gitleaksSrcDir: "."
semgrepFilename: "semgrep-sast-report.json" # Filename for the semgrep sast report (e.g. semgrep-sast-report.json)
semgrepRules: "p/default" # Semgrep rules to use (e.g. p/default)
semgrepExperimental: false # Whether to use experimental semgrep rules (true/false)
coverageFile: "" #"coverage/cobertura-coverage.xml" # Externally generated code coverage file
semgrepSrcDir: "." # Target directory for semgrep scan (e.g. ./cmd/portage)

# Image Publish Configuration
imagePublish:
enabled: false # Enable/Disable the image publish pipeline (true/false)
bundleTag: "ghcr.io/easy-up/gatecheck:latest" # Image tag for gatecheck bundle image blob (e.g. my-org/my-app:latest)

# Deploy Configuration
deploy:
enabled: true # Enable/Disable the deploy pipeline (true/false). When true, the .gatecheck.yml file is used, otherwise the default gatecheck config is used.
gatecheckConfigFilename: ".custom-gatecheck.yml" # Filename for gatecheck config (e.g. gatecheck-config.json)
submit: false # Whether to submit the artifacts to the configured API endpoint (true/false)
successWebhooks:
- url: "http://localhost:5168/Build/SubmitArtifacts" # Using the same endpoint from .custom-gatecheck.yml for consistency
authorizationVar: "DEPLOY_WEBHOOK_AUTH_TOKEN" # Environment variable containing the auth token
40 changes: 34 additions & 6 deletions pkg/archive/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/olekukonko/tablewriter"
"io"
"log/slog"
"os"
Expand All @@ -19,6 +18,8 @@ import (
"strings"
"time"

"github.com/olekukonko/tablewriter"

"github.com/dustin/go-humanize"
"github.com/gatecheckdev/gatecheck/pkg/format"
)
Expand Down Expand Up @@ -99,25 +100,31 @@ func NewBundle() *Bundle {

func GetContext() (*GitContext, error) {
// Get git information
slog.Debug("attempting to get git context")
gitCmd := exec.Command("git", "rev-parse", "HEAD")
commitHash, err := gitCmd.Output()
if err != nil {
// If rev-parse fails either the git executable is missing or corrupt, or we are not in a git repo
slog.Debug("failed to get git commit hash, skipping git context", "error", err)
// If we're not in a git repo then Context should just be nil
return nil, nil
}
slog.Debug("got git commit hash", "hash", strings.TrimSpace(string(commitHash)))

gitCmd = exec.Command("git", "show", "-s", "--format=%cI%n%B", "HEAD")
commitDateAndMessageBytes, err := gitCmd.Output()
if err != nil {
slog.Error("failed to get commit date and message", "error", err)
return nil, fmt.Errorf("failed to get commit date: %w", err)
}
slog.Debug("got commit date and message", "raw", string(commitDateAndMessageBytes))

commitDateAndMessage := strings.SplitN(string(commitDateAndMessageBytes), "\n", 2)
commitDate := commitDateAndMessage[0]
commitMessage := ""
if len(commitDateAndMessage) > 1 {
commitMessage = commitDateAndMessage[1]
}
if err != nil {
return nil, fmt.Errorf("failed to get commit date: %w", err)
}

// Get git branch name
gitCmd = exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD")
Expand Down Expand Up @@ -152,6 +159,12 @@ func GetContext() (*GitContext, error) {
return nil, fmt.Errorf("failed to parse commit date: %w", err)
}

slog.Debug("successfully created git context",
"commit", strings.TrimSpace(string(commitHash)),
"branch", strings.TrimSpace(string(branchName)),
"date", commitDateParsed,
"status_count", len(gitFileStatuses))

return &GitContext{
CommitHash: strings.TrimSpace(string(commitHash)),
CommitDate: commitDateParsed,
Expand Down Expand Up @@ -389,10 +402,25 @@ func TarGzipBundle(dst io.Writer, bundle *Bundle) (int64, error) {
if bundle == nil {
return 0, errors.New("cannot write nil bundle")
}

slog.Debug("preparing bundle for tar.gz",
"file_count", len(bundle.content),
"has_git_context", bundle.manifest.Context != nil)

tarballBuffer := new(bytes.Buffer)
tarWriter := tar.NewWriter(tarballBuffer)
manifestBytes, _ := json.Marshal(bundle.manifest)
_ = bundle.AddFrom(bytes.NewReader(manifestBytes), "gatecheck-manifest.json", nil)
manifestBytes, err := json.Marshal(bundle.manifest)
if err != nil {
slog.Error("failed to marshal manifest", "error", err)
return 0, fmt.Errorf("failed to marshal manifest: %w", err)
}
slog.Debug("manifest content", "json", string(manifestBytes))

err = bundle.AddFrom(bytes.NewReader(manifestBytes), "gatecheck-manifest.json", nil)
if err != nil {
slog.Error("failed to add manifest to bundle", "error", err)
return 0, err
}

for label, data := range bundle.content {
// Using bytes.Buffer so IO errors are unlikely
Expand Down
26 changes: 23 additions & 3 deletions pkg/gatecheck/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,45 @@ import (
// If the bundle already exist, use CreateBundle.
// this function will completely overwrite an existing bundle
func CreateBundle(dstBundle io.Writer, src io.Reader, label string, tags []string) error {
slog.Debug("add to source file content to bundle", "label", label, "tags", tags)
slog.Debug("creating new bundle")
srcContent, err := io.ReadAll(src)
if err != nil {
slog.Error("failed to read source content", "error", err)
return err
}

gitContext, err := archive.GetContext()
if err != nil {
slog.Error("failed to get git context", "error", err)
return err
}
if gitContext == nil {
slog.Warn("no git context available, bundle will not include git information")
} else {
slog.Info("git context for bundle",
"commit", gitContext.CommitHash,
"branch", gitContext.Branch,
"date", gitContext.CommitDate,
"message", gitContext.CommitMessage,
"status_count", len(gitContext.Status))
}

bundle := archive.NewBundle()
bundle.SetContext(gitContext)
bundle.Add(srcContent, label, tags)

slog.Debug("write bundle")
slog.Debug("writing bundle to tar.gz")
n, err := archive.TarGzipBundle(dstBundle, bundle)
if err != nil {
slog.Error("failed to write bundle", "error", err)
return err
}

slog.Info("bundle write success", "bytes_written", n, "label", label, "tags", tags)
slog.Info("bundle write success",
"bytes_written", n,
"label", label,
"tags", tags,
"has_git_context", gitContext != nil)

return nil
}
Expand All @@ -50,6 +67,9 @@ func AppendToBundle(bundleRWS io.ReadWriteSeeker, src io.Reader, label string, t

// Validate the GitContext in the bundle
newContext, err := archive.GetContext()
if err != nil {
return err
}
if !compareContext(newContext, bundle.Manifest().Context) {
// The current context is different from the existing context. Clear all stale artifacts.
slog.Info("the git context hash changed, clearing stale bundle contents")
Expand Down
Loading

0 comments on commit d34dba6

Please sign in to comment.