Cybersecurity-Projects/PROJECTS/intermediate/secrets-scanner/internal/cli/scan.go

120 lines
2.2 KiB
Go

// ©AngelaMos | 2026
// scan.go
package cli
import (
"context"
"os"
"time"
"github.com/spf13/cobra"
"github.com/CarterPerez-dev/portia/internal/engine"
"github.com/CarterPerez-dev/portia/internal/hibp"
"github.com/CarterPerez-dev/portia/internal/reporter"
"github.com/CarterPerez-dev/portia/internal/rules"
"github.com/CarterPerez-dev/portia/internal/source"
"github.com/CarterPerez-dev/portia/internal/ui"
"github.com/CarterPerez-dev/portia/pkg/types"
)
var scanCmd = &cobra.Command{
Use: "scan [path]",
Short: "Scan a directory for secrets",
Args: cobra.MaximumNArgs(1),
RunE: runScan,
}
func runScan(cmd *cobra.Command, args []string) error {
path := "."
if len(args) > 0 {
path = args[0]
}
ui.PrintBanner()
reg := rules.NewRegistry()
rules.RegisterBuiltins(reg)
applyRuleConfig(reg)
src := source.NewDirectory(path, maxSize, excludes)
return executeScan(cmd.Context(), reg, src)
}
func executeScan(
ctx context.Context,
reg *rules.Registry,
src source.Source,
) error {
spin := ui.NewSpinner("Scanning for secrets...")
if !verbose {
spin.Start()
}
start := time.Now()
p := engine.NewPipeline(reg)
p.SetVerbose(verbose)
result, err := p.Run(ctx, src)
spin.Stop()
if err != nil {
return err
}
result.Duration = time.Since(start)
if enableHIBP && len(result.Findings) > 0 {
checkHIBP(ctx, result)
}
rep := reporter.New(format)
return rep.Report(os.Stdout, result)
}
func checkHIBP(ctx context.Context, result *types.ScanResult) {
client := hibp.NewClient()
spin := ui.NewSpinner("Checking HIBP breach database...")
spin.Start()
defer spin.Stop()
for i := range result.Findings {
f := &result.Findings[i]
if f.Secret == "" {
continue
}
if f.RuleID != "generic-password" &&
f.RuleID != "generic-secret" {
f.HIBPStatus = types.HIBPSkipped
continue
}
res, err := client.Check(ctx, f.Secret)
result.HIBPChecked++
if err != nil {
f.HIBPStatus = types.HIBPError
continue
}
if res.Breached {
f.HIBPStatus = types.HIBPBreached
f.BreachCount = res.Count
result.HIBPBreached++
} else {
f.HIBPStatus = types.HIBPClean
}
}
}
func applyRuleConfig(reg *rules.Registry) {
if cfg == nil {
return
}
if len(cfg.Rules.Disable) > 0 {
reg.Disable(cfg.Rules.Disable...)
}
}