reporting

package
v0.0.0-...-e601d7c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 20, 2026 License: MIT Imports: 18 Imported by: 0

README

Security Reporting Integration

This package provides integration with external security reporting systems for container image scan results.

Features

DefectDojo Integration

Upload vulnerability scan results to DefectDojo, an open-source application vulnerability correlation and security orchestration tool.

Configuration:

security:
  reporting:
    defectdojo:
      enabled: true
      url: "https://defectdojo.example.com"
      apiKey: "${secret:defectdojo-api-key}"
      engagementId: 123  # Use existing engagement
      # OR create new engagement:
      engagementName: "Container Scan"
      productName: "MyProduct"
      autoCreate: true
      tags: ["ci", "production"]
      environment: "production"  # Optional; must already exist in DefectDojo if set

Programmatic Usage:

client := reporting.NewDefectDojoClient(url, apiKey)
config := &reporting.DefectDojoUploaderConfig{
    EngagementID: 123,
}
result, err := client.UploadScanResult(ctx, scanResult, "myimage@sha256:...", config)
Workflow Summary

Track and display a comprehensive summary of all security operations with timing information.

Usage:

// Create summary
summary := reporting.NewWorkflowSummary("myimage:latest")

// Record operations
summary.RecordSBOM(sbomResult, nil, duration, "sbom.json")
summary.RecordScan(scan.ScanToolGrype, scanResult, nil, duration, "v1.2.3")
summary.RecordSigning(signResult, nil, duration)
summary.RecordUpload("defectdojo", nil, url, duration)

// Display summary
summary.Display()

Output Example:

╔══════════════════════════════════════════════════════════════════╗
║                    SECURITY WORKFLOW SUMMARY                      ║
╠══════════════════════════════════════════════════════════════════╣
║ Image: myimage@sha256:...                                          ║
║ Duration: 2m34s                                                    ║
╠══════════════════════════════════════════════════════════════════╣
║ 📋 SBOM Generation                                                 ║
║   Status: ✅ SUCCESS                                              ║
║   Packages: 142                                                    ║
╠══════════════════════════════════════════════════════════════════╣
║ 🔍 Vulnerability Scanning                                            ║
║   Grype: 3 critical, 7 high, 12 medium vulnerabilities            ║
║   Trivy: 3 critical, 6 high, 11 medium vulnerabilities            ║
║   Merged: 3 critical, 7 high, 12 medium (deduplicated)           ║
╠══════════════════════════════════════════════════════════════════╣
║ 🔐 Image Signing                                                    ║
║   Status: ✅ SUCCESS                                              ║
║   Method: Keyless (OIDC)                                          ║
╠══════════════════════════════════════════════════════════════════╣
║ 📤 Report Uploads                                                   ║
║   DefectDojo: ✅ uploaded                                         ║
╚══════════════════════════════════════════════════════════════════╝

CLI Usage

Scan with Reporting
# Scan and upload to DefectDojo
sc image scan \
  --image myimage@sha256:... \
  --tool all \
  --upload-defectdojo \
  --defectdojo-url https://defectdojo.example.com \
  --defectdojo-api-key $DEFECTDOJO_API_KEY

DefectDojo Setup

Prerequisites
  1. DefectDojo instance running (v2.0+)
  2. API key with appropriate permissions
  3. Product and Engagement created (or enable auto-create)
API Key Setup
# Get API key from DefectDojo
# Settings > API Keys > Create API Key
export DEFECTDOJO_API_KEY="your-api-key"
export DEFECTDOJO_URL="https://defectdojo.example.com"
Auto-Create Mode

When autoCreate: true, the system will automatically create:

  • Product if it doesn't exist
  • Engagement if it doesn't exist
security:
  reporting:
    defectdojo:
      enabled: true
      url: "${DEFECTDOJO_URL}"
      apiKey: "${DEFECTDOJO_API_KEY}"
      productName: "MyProduct"
      engagementName: "Container Scan"
      autoCreate: true

If you set environment, the value must already exist in the target DefectDojo instance. Leave it unset if you do not manage environments there.

Implementation Details

DefectDojo API

The DefectDojo client uses the REST API v2:

  • Product management: /api/v2/products/
  • Engagement management: /api/v2/engagements/
  • Scan import: /api/v2/import-scan/

Supports:

  • Auto-creation of products and engagements
  • Tag-based organization
  • Environment labeling

Error Handling

All reporting operations follow the fail-open philosophy:

  • Upload failures are logged as warnings
  • Don't block the main security workflow
  • Errors are tracked in the workflow summary
if e.Summary != nil {
    e.Summary.RecordUpload("defectdojo", err, url, duration)
}

Performance Considerations

  • DefectDojo upload: 1-3 seconds depending on network
  • The import call is a single network round-trip after scan completion

Security Best Practices

  1. API Keys: Use environment variables or secret management

    apiKey: "${secret:defectdojo-api-key}"
    
  2. HTTPS: Always use HTTPS for API endpoints

  3. Access Control: Limit API key permissions in external systems

Troubleshooting

DefectDojo Upload Fails
Error: getting engagement: engagement ID 123 not found

Solution: Enable auto-create or verify engagement exists:

autoCreate: true
engagementName: "My Engagement"
productName: "My Product"

Contributing

When adding new reporting integrations:

  1. Create client in separate file (e.g., defectdojo.go)
  2. Implement UploadXXX function
  3. Add configuration to pkg/security/config.go
  4. Update executor's UploadReports method
  5. Add CLI flags in pkg/cmd/cmd_image/scan.go
  6. Update this README

References

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildScanResultsComment

func BuildScanResultsComment(imageRef string, result *scan.ScanResult, uploads []*UploadSummary) string

BuildScanResultsComment renders a concise markdown summary for PR comments.

func NewSARIFFromScanResult

func NewSARIFFromScanResult(result *scan.ScanResult, imageRef string) ([]byte, error)

NewSARIFFromScanResult converts a normalized scan result into SARIF 2.1.0.

Types

type DefectDojoClient

type DefectDojoClient struct {
	BaseURL    string
	APIKey     string
	HTTPClient *http.Client
}

DefectDojoClient handles interactions with DefectDojo API API Documentation: https://defectdojo.github.io/django-DefectDojo/rest/api/

func NewDefectDojoClient

func NewDefectDojoClient(baseURL, apiKey string) *DefectDojoClient

NewDefectDojoClient creates a new DefectDojo client. Warns if the URL is not HTTPS (API key would be sent in cleartext).

func (*DefectDojoClient) UploadScanResult

func (c *DefectDojoClient) UploadScanResult(ctx context.Context, result *scan.ScanResult, imageRef string, config *DefectDojoUploaderConfig) (*ImportScanResponse, error)

UploadScanResult uploads scan results to DefectDojo. Uses reimport when a test with the same title already exists in the engagement to avoid creating duplicate findings. Falls back to import-scan for new tests.

type DefectDojoEngagement

type DefectDojoEngagement struct {
	ID          int    `json:"id"`
	Name        string `json:"name"`
	Product     int    `json:"product"`
	TargetStart string `json:"target_start"`
	TargetEnd   string `json:"target_end"`
	Status      string `json:"status"`
}

DefectDojoEngagement represents a DefectDojo engagement

type DefectDojoProduct

type DefectDojoProduct struct {
	ID          int    `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
	ProductType int    `json:"prod_type"`
}

DefectDojoProduct represents a DefectDojo product

type DefectDojoTest

type DefectDojoTest struct {
	ID          int    `json:"id"`
	Title       string `json:"title"`
	Engagement  int    `json:"engagement"`
	TestType    int    `json:"test_type"`
	TargetStart string `json:"target_start"`
	TargetEnd   string `json:"target_end"`
}

DefectDojoTest represents a DefectDojo test

type DefectDojoUploaderConfig

type DefectDojoUploaderConfig struct {
	EngagementID   int
	EngagementName string
	ProductID      int
	ProductName    string
	TestType       string
	Tags           []string
	Environment    string
	AutoCreate     bool
}

DefectDojoUploaderConfig contains configuration for uploading to DefectDojo

type ImportScanResponse

type ImportScanResponse struct {
	ID               int `json:"id"`
	Test             int `json:"test"`
	Product          int `json:"product"`
	Engagement       int `json:"engagement"`
	NumberOfFindings int `json:"number_of_findings"`
}

ImportScanResponse represents the response from importing a scan

type ProvenanceSummary

type ProvenanceSummary struct {
	Success  bool
	Error    error
	Format   string
	Duration time.Duration
	Attached bool
}

ProvenanceSummary tracks provenance generation results

type SBOMSummary

type SBOMSummary struct {
	Success      bool
	Error        error
	PackageCount int
	Format       string
	Generator    string
	Attached     bool
	Signed       bool
	Duration     time.Duration
	OutputPath   string
}

SBOMSummary tracks SBOM generation results

type ScanSummary

type ScanSummary struct {
	Tool        scan.ScanTool
	Success     bool
	Error       error
	ScanResult  *scan.ScanResult
	Duration    time.Duration
	ToolVersion string
}

ScanSummary tracks vulnerability scan results

type SigningSummary

type SigningSummary struct {
	Success  bool
	Error    error
	Keyless  bool
	SignedAt time.Time
	Duration time.Duration
}

SigningSummary tracks signing results

type UploadSummary

type UploadSummary struct {
	Target   string // "defectdojo"
	Success  bool
	Error    error
	URL      string
	Duration time.Duration
}

UploadSummary tracks report upload results

type WorkflowSummary

type WorkflowSummary struct {
	ImageRef         string
	StartTime        time.Time
	EndTime          time.Time
	SBOMResult       *SBOMSummary
	ScanResults      []*ScanSummary
	MergedResult     *ScanSummary
	SigningResult    *SigningSummary
	ProvenanceResult *ProvenanceSummary
	UploadResults    []*UploadSummary
}

WorkflowSummary tracks the results of all security operations

func NewWorkflowSummary

func NewWorkflowSummary(imageRef string) *WorkflowSummary

NewWorkflowSummary creates a new workflow summary

func (*WorkflowSummary) Display

func (w *WorkflowSummary) Display()

Display prints a formatted summary to stdout

func (*WorkflowSummary) Duration

func (w *WorkflowSummary) Duration() time.Duration

Duration returns the total workflow duration

func (*WorkflowSummary) Finalize

func (w *WorkflowSummary) Finalize()

Finalize marks the workflow as complete

func (*WorkflowSummary) HasFailures

func (w *WorkflowSummary) HasFailures() bool

HasFailures returns true if any operation failed

func (*WorkflowSummary) RecordMergedScan

func (w *WorkflowSummary) RecordMergedScan(result *scan.ScanResult)

RecordMergedScan records merged scan result

func (*WorkflowSummary) RecordProvenance

func (w *WorkflowSummary) RecordProvenance(format string, err error, duration time.Duration, attached bool)

RecordProvenance records provenance generation result

func (*WorkflowSummary) RecordSBOM

func (w *WorkflowSummary) RecordSBOM(result *sbom.SBOM, err error, duration time.Duration, outputPath string)

RecordSBOM records SBOM generation result

func (*WorkflowSummary) RecordScan

func (w *WorkflowSummary) RecordScan(tool scan.ScanTool, result *scan.ScanResult, err error, duration time.Duration, toolVersion string)

RecordScan records a scan result

func (*WorkflowSummary) RecordSigning

func (w *WorkflowSummary) RecordSigning(result *signing.SignResult, err error, duration time.Duration)

RecordSigning records signing result

func (*WorkflowSummary) RecordUpload

func (w *WorkflowSummary) RecordUpload(target string, err error, url string, duration time.Duration)

RecordUpload records a report upload result

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL