cmd

package
v0.1.5-beta Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2026 License: GPL-3.0 Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ExitCodeSuccess  = 0 // No findings or all below threshold
	ExitCodeFindings = 1 // Findings detected
	ExitCodeError    = 2 // Tool error (network, config, etc.)
	ExitCodeCritical = 3 // Critical vulnerabilities found
)

Exit codes for CI/CD integration

Variables

View Source
var AutoCmd = &cobra.Command{
	Use:   "auto",
	Short: "Manage automatic scanning",
	Long:  `Enable or disable automatic scanning on package installs`,
}
View Source
var ConfigCmd = &cobra.Command{
	Use:   "config",
	Short: "Manage configuration",
	Long:  `View and modify SecChain configuration settings`,
}
View Source
var DoctorCmd = &cobra.Command{
	Use:   "doctor",
	Short: "Check system health",
	Long: `Check Docker, ClamAV, shell hooks, and other dependencies.
Perform a full health check of the SecChain environment.`,
	Run: func(cmd *cobra.Command, args []string) {

		checks := runHealthChecks()

		formatter := output.NewFormatter("table", true, false)

		outputChecks := make([]output.HealthCheck, len(checks))
		for i, check := range checks {
			outputChecks[i] = output.HealthCheck{
				Name:       check.Name,
				Passed:     check.Passed,
				Message:    check.Message,
				Suggestion: check.Suggestion,
			}
		}
		result := formatter.FormatDoctor(outputChecks)
		fmt.Print(result)

		criticalFailures := 0
		for _, check := range checks {
			if !check.Passed && isCriticalCheck(check.Name) {
				criticalFailures++
			}
		}

		if criticalFailures > 0 {
			fmt.Printf("\n❌ %d critical health check(s) failed\n", criticalFailures)
			os.Exit(1)
		} else {
			fmt.Printf("\n✅ All health checks passed\n")
		}
	},
}
View Source
var ReportCmd = &cobra.Command{
	Use:   "report",
	Short: "Show scan reports",
	Long:  `Display scan results and history`,
	Run: func(cmd *cobra.Command, args []string) {

		cacheManager, err := cache.NewCache()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error initializing cache: %v\n", err)
			os.Exit(1)
		}
		defer cacheManager.Close()

		var results []*scanner.ScanResult

		if reportPkg != "" {

			result, err := cacheManager.GetScanResult(reportPkg, "latest", "")
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error getting package report: %v\n", err)
				os.Exit(1)
			}
			if result == nil {
				fmt.Printf("No scan results found for package: %s\n", reportPkg)
				return
			}

			results = []*scanner.ScanResult{{}}
		} else if reportHistory {

			fmt.Println("📜 Scan History:")
			fmt.Println("   (History feature not yet implemented)")
			return
		} else {

			fmt.Println("📊 Last Scan Report:")
			fmt.Println("   (Last scan feature not yet implemented)")
			return
		}

		formatter := output.NewFormatter(reportFormat, true, false)
		output, err := formatter.Format(results)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error formatting results: %v\n", err)
			os.Exit(1)
		}

		fmt.Print(output)
	},
}
View Source
var ScanCmd = &cobra.Command{
	Use:   "scan [path]",
	Short: "Scan a local project directory or package",
	Long: `Scan a local project directory or package before installing.
Supports multiple ecosystems: node, python, rust, go, ruby`,
	Run: func(cmd *cobra.Command, args []string) {
		ctx := context.Background()

		configManager, cfgErr := config.NewManager()
		if cfgErr != nil {
			fmt.Fprintf(os.Stderr, "Error loading config: %v\n", cfgErr)
			os.Exit(ExitCodeError)
		}
		cfg := configManager.Get()
		minSeverity := cfg.MinSeverity

		pipeline := scanner.NewPipeline()

		var results []*scanner.ScanResult
		var err error
		var projectPath string

		if scanPkg != "" {

			if scanVersion == "" {
				scanVersion = "latest"
			}

			if scanEcosystem == "" {
				fmt.Fprintf(os.Stderr, "Error: --ecosystem is required when scanning a package\n")
				os.Exit(ExitCodeError)
			}

			fmt.Printf("Scanning package %s@%s (%s)...\n", scanPkg, scanVersion, scanEcosystem)
			result, err := pipeline.ScanPackage(ctx, scanPkg, scanVersion, scanEcosystem, minSeverity)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error scanning package: %v\n", err)
				os.Exit(ExitCodeError)
			}
			results = []*scanner.ScanResult{result}
		} else if len(args) > 0 {

			projectPath = args[0]
			if !filepath.IsAbs(projectPath) {
				cwd, _ := os.Getwd()
				projectPath = filepath.Join(cwd, projectPath)
			}

			fmt.Printf("Scanning project directory: %s\n", projectPath)
			results, err = pipeline.ScanProject(ctx, projectPath, minSeverity)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error scanning project: %v\n", err)
				os.Exit(ExitCodeError)
			}
		} else {
			fmt.Fprintf(os.Stderr, "Error: Either specify a package with --pkg or provide a project path\n")
			os.Exit(ExitCodeError)
		}

		if scanBaseline != "" || fileExists(filepath.Join(projectPath, config.BaselineFile)) {
			baselinePath := scanBaseline
			if baselinePath == "" {
				baselinePath = filepath.Join(projectPath, config.BaselineFile)
			}
			bm := config.NewBaselineManager(filepath.Dir(baselinePath))
			baseline, _ := bm.LoadBaseline()
			if baseline != nil {
				fmt.Printf("Applying baseline filter: %d packages in baseline\n", len(baseline.Packages))
				results = bm.FilterWithBaseline(results, baseline)
			}
		}

		if scanIgnore != "" || fileExists(filepath.Join(projectPath, config.IgnoreFile)) {
			ignorePath := scanIgnore
			if ignorePath == "" {
				ignorePath = filepath.Join(projectPath, config.IgnoreFile)
			}
			bm := config.NewBaselineManager(filepath.Dir(ignorePath))
			ignoreList, _ := bm.LoadIgnoreList()
			if ignoreList != nil {
				results = bm.FilterWithIgnoreList(results, ignoreList)
			}
		}

		if scanSarifOutput != "" || scanFormat == "sarif" {
			sarifFile := scanSarifOutput
			if sarifFile == "" {
				sarifFile = "secchain-results.sarif"
			}
			version := "0.1.5"
			if err := output.WriteSARIFFile(results, sarifFile, version); err != nil {
				fmt.Fprintf(os.Stderr, "Error writing SARIF file: %v\n", err)
			} else {
				fmt.Printf("SARIF report written to: %s\n", sarifFile)
			}
		}

		if scanFormat != "sarif" || scanSarifOutput == "" {
			formatter := output.NewFormatter(scanFormat, true, false)
			out, err := formatter.Format(results)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error formatting results: %v\n", err)
				os.Exit(ExitCodeError)
			}
			fmt.Print(out)
		}

		exitCode := calculateExitCode(results, scanStrict)

		if exitCode == ExitCodeSuccess {
			fmt.Printf("\n✅ All packages passed security scan\n")
		} else if exitCode == ExitCodeCritical {
			fmt.Printf("\n❌ Critical vulnerabilities found - immediate action required\n")
		} else if scanStrict {
			fmt.Printf("\n❌ Risks detected and strict mode enabled - aborting\n")
		} else if !scanLogOnly {
			fmt.Printf("\n⚠️  Risks detected - review results above\n")
		}

		if scanExitCode {
			os.Exit(exitCode)
		}
	},
}
View Source
var UpdateRulesCmd = &cobra.Command{
	Use:   "update-rules",
	Short: "Update YARA rules and CVE DB cache",
	Long:  `Download and update YARA rules and CVE database cache`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("🔄 Updating YARA rules and CVE database...")

		yaraScanner := scanner.NewYARAScanner()
		if err := yaraScanner.UpdateRules(); err != nil {
			fmt.Fprintf(os.Stderr, "Error updating YARA rules: %v\n", err)
			os.Exit(1)
		}
		fmt.Println("✅ YARA rules updated")

		cveChecker := scanner.NewCVEChecker()
		if err := cveChecker.Init(); err != nil {
			fmt.Fprintf(os.Stderr, "Error initializing CVE checker: %v\n", err)
			os.Exit(1)
		}
		defer cveChecker.Close()

		fmt.Println("✅ CVE cache updated")

		fmt.Println("\n🎉 All rules and caches updated successfully!")
	},
}
View Source
var VersionCmd = &cobra.Command{
	Use:   "version",
	Short: "Show SecChain version",
	Long:  `Display the current version of SecChain`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("SecChain CLI Security Tool")
		fmt.Println("Version: 0.1.5-beta")
		fmt.Println("Build: development")
		fmt.Println("\n🛡️  Protecting your dependencies from supply chain attacks")
	},
}

Functions

This section is empty.

Types

type HealthCheck

type HealthCheck struct {
	Name       string
	Passed     bool
	Message    string
	Suggestion string
}

HealthCheck represents a health check result

Jump to

Keyboard shortcuts

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