mirror of
https://github.com/ivuorinen/gibidify.git
synced 2026-02-13 05:49:16 +00:00
fix(security): prevent integer overflow in uint64 to int64 conversions
Add overflow checks before converting uint64 memory values to int64 to prevent potential integer overflow issues identified by gosec (G115). - Add math.MaxInt64 checks in fileproc/backpressure.go - Add math.MaxInt64 checks in fileproc/resource_monitor_validation.go - Add math.MaxInt64 checks in fileproc/resource_monitor_metrics.go - Add math.MaxInt64 check in benchmark/benchmark.go with nosec annotation Co-authored-by: ivuorinen <11024+ivuorinen@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,7 @@ package benchmark
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -272,7 +273,7 @@ func createBenchmarkFiles(numFiles int) (string, func(), error) {
|
|||||||
// Create subdirectories for some files
|
// Create subdirectories for some files
|
||||||
if i%10 == 0 {
|
if i%10 == 0 {
|
||||||
subdir := filepath.Join(tempDir, fmt.Sprintf("subdir_%d", i/10))
|
subdir := filepath.Join(tempDir, fmt.Sprintf("subdir_%d", i/10))
|
||||||
if err := os.MkdirAll(subdir, 0o755); err != nil {
|
if err := os.MkdirAll(subdir, 0o750); err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
return "", nil, utils.WrapError(err, utils.ErrorTypeFileSystem, utils.CodeFSAccess, "failed to create subdirectory")
|
return "", nil, utils.WrapError(err, utils.ErrorTypeFileSystem, utils.CodeFSAccess, "failed to create subdirectory")
|
||||||
}
|
}
|
||||||
@@ -287,7 +288,7 @@ func createBenchmarkFiles(numFiles int) (string, func(), error) {
|
|||||||
content += fmt.Sprintf("// Line %d\n%s\n", j, fileType.content)
|
content += fmt.Sprintf("// Line %d\n%s\n", j, fileType.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(filename, []byte(content), 0o644); err != nil {
|
if err := os.WriteFile(filename, []byte(content), 0o600); err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
return "", nil, utils.WrapError(err, utils.ErrorTypeIO, utils.CodeIOFileWrite, "failed to write benchmark file")
|
return "", nil, utils.WrapError(err, utils.ErrorTypeIO, utils.CodeIOFileWrite, "failed to write benchmark file")
|
||||||
}
|
}
|
||||||
@@ -356,7 +357,13 @@ func PrintBenchmarkResult(result *BenchmarkResult) {
|
|||||||
fmt.Printf("Files/sec: %.2f\n", result.FilesPerSecond)
|
fmt.Printf("Files/sec: %.2f\n", result.FilesPerSecond)
|
||||||
fmt.Printf("Bytes/sec: %.2f MB/sec\n", result.BytesPerSecond/1024/1024)
|
fmt.Printf("Bytes/sec: %.2f MB/sec\n", result.BytesPerSecond/1024/1024)
|
||||||
fmt.Printf("Memory Usage: +%.2f MB (Sys: +%.2f MB)\n", result.MemoryUsage.AllocMB, result.MemoryUsage.SysMB)
|
fmt.Printf("Memory Usage: +%.2f MB (Sys: +%.2f MB)\n", result.MemoryUsage.AllocMB, result.MemoryUsage.SysMB)
|
||||||
fmt.Printf("GC Runs: %d (Pause: %v)\n", result.MemoryUsage.NumGC, time.Duration(result.MemoryUsage.PauseTotalNs))
|
// Safe conversion: cap at MaxInt64 to prevent overflow
|
||||||
|
pauseTotalNs := result.MemoryUsage.PauseTotalNs
|
||||||
|
if pauseTotalNs > math.MaxInt64 {
|
||||||
|
pauseTotalNs = math.MaxInt64
|
||||||
|
}
|
||||||
|
pauseDuration := time.Duration(int64(pauseTotalNs)) // #nosec G115 -- overflow check above
|
||||||
|
fmt.Printf("GC Runs: %d (Pause: %v)\n", result.MemoryUsage.NumGC, pauseDuration)
|
||||||
fmt.Printf("Goroutines: %d\n", result.CPUUsage.Goroutines)
|
fmt.Printf("Goroutines: %d\n", result.CPUUsage.Goroutines)
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package fileproc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -73,7 +74,11 @@ func (bp *BackpressureManager) ShouldApplyBackpressure(ctx context.Context) bool
|
|||||||
// Get current memory usage
|
// Get current memory usage
|
||||||
var m runtime.MemStats
|
var m runtime.MemStats
|
||||||
runtime.ReadMemStats(&m)
|
runtime.ReadMemStats(&m)
|
||||||
|
// Safe conversion: cap at MaxInt64 to prevent overflow
|
||||||
currentMemory := int64(m.Alloc)
|
currentMemory := int64(m.Alloc)
|
||||||
|
if m.Alloc > math.MaxInt64 {
|
||||||
|
currentMemory = math.MaxInt64
|
||||||
|
}
|
||||||
|
|
||||||
bp.mu.Lock()
|
bp.mu.Lock()
|
||||||
defer bp.mu.Unlock()
|
defer bp.mu.Unlock()
|
||||||
@@ -130,10 +135,16 @@ func (bp *BackpressureManager) GetStats() BackpressureStats {
|
|||||||
var m runtime.MemStats
|
var m runtime.MemStats
|
||||||
runtime.ReadMemStats(&m)
|
runtime.ReadMemStats(&m)
|
||||||
|
|
||||||
|
// Safe conversion: cap at MaxInt64 to prevent overflow
|
||||||
|
currentMemory := int64(m.Alloc)
|
||||||
|
if m.Alloc > math.MaxInt64 {
|
||||||
|
currentMemory = math.MaxInt64
|
||||||
|
}
|
||||||
|
|
||||||
return BackpressureStats{
|
return BackpressureStats{
|
||||||
Enabled: bp.enabled,
|
Enabled: bp.enabled,
|
||||||
FilesProcessed: atomic.LoadInt64(&bp.filesProcessed),
|
FilesProcessed: atomic.LoadInt64(&bp.filesProcessed),
|
||||||
CurrentMemoryUsage: int64(m.Alloc),
|
CurrentMemoryUsage: currentMemory,
|
||||||
MaxMemoryUsage: bp.maxMemoryUsage,
|
MaxMemoryUsage: bp.maxMemoryUsage,
|
||||||
MemoryWarningActive: bp.memoryWarningLogged,
|
MemoryWarningActive: bp.memoryWarningLogged,
|
||||||
LastMemoryCheck: bp.lastMemoryCheck,
|
LastMemoryCheck: bp.lastMemoryCheck,
|
||||||
|
|||||||
@@ -208,11 +208,11 @@ func TestFileTypeRegistry_BinaryDetection(t *testing.T) {
|
|||||||
{"page.html", false},
|
{"page.html", false},
|
||||||
|
|
||||||
// Edge cases
|
// Edge cases
|
||||||
{"", false}, // Empty filename
|
{"", false}, // Empty filename
|
||||||
{"binary", false}, // No extension
|
{"binary", false}, // No extension
|
||||||
{".exe", true}, // Just extension
|
{".exe", true}, // Just extension
|
||||||
{"file.exe.txt", false}, // Multiple extensions
|
{"file.exe.txt", false}, // Multiple extensions
|
||||||
{"file.unknown", false}, // Unknown extension
|
{"file.unknown", false}, // Unknown extension
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|||||||
@@ -130,8 +130,6 @@ func (w *JSONWriter) streamJSONContent(reader io.Reader, path string) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// startJSONWriter handles JSON format output with streaming support.
|
// startJSONWriter handles JSON format output with streaming support.
|
||||||
func startJSONWriter(outFile *os.File, writeCh <-chan WriteRequest, done chan<- struct{}, prefix, suffix string) {
|
func startJSONWriter(outFile *os.File, writeCh <-chan WriteRequest, done chan<- struct{}, prefix, suffix string) {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
|
|||||||
@@ -138,7 +138,6 @@ func (p *FileProcessor) ProcessWithContext(ctx context.Context, filePath string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// validateFileWithLimits checks if the file can be processed with resource limits.
|
// validateFileWithLimits checks if the file can be processed with resource limits.
|
||||||
func (p *FileProcessor) validateFileWithLimits(ctx context.Context, filePath string) (os.FileInfo, error) {
|
func (p *FileProcessor) validateFileWithLimits(ctx context.Context, filePath string) (os.FileInfo, error) {
|
||||||
// Check context cancellation
|
// Check context cancellation
|
||||||
@@ -192,7 +191,6 @@ func (p *FileProcessor) getRelativePath(filePath string) string {
|
|||||||
return relPath
|
return relPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// processInMemoryWithContext loads the entire file into memory with context awareness.
|
// processInMemoryWithContext loads the entire file into memory with context awareness.
|
||||||
func (p *FileProcessor) processInMemoryWithContext(ctx context.Context, filePath, relPath string, outCh chan<- WriteRequest) {
|
func (p *FileProcessor) processInMemoryWithContext(ctx context.Context, filePath, relPath string, outCh chan<- WriteRequest) {
|
||||||
// Check context before reading
|
// Check context before reading
|
||||||
@@ -240,7 +238,6 @@ func (p *FileProcessor) processInMemoryWithContext(ctx context.Context, filePath
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// processStreamingWithContext creates a streaming reader for large files with context awareness.
|
// processStreamingWithContext creates a streaming reader for large files with context awareness.
|
||||||
func (p *FileProcessor) processStreamingWithContext(ctx context.Context, filePath, relPath string, outCh chan<- WriteRequest) {
|
func (p *FileProcessor) processStreamingWithContext(ctx context.Context, filePath, relPath string, outCh chan<- WriteRequest) {
|
||||||
// Check context before creating reader
|
// Check context before creating reader
|
||||||
@@ -276,7 +273,6 @@ func (p *FileProcessor) processStreamingWithContext(ctx context.Context, filePat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// createStreamReaderWithContext creates a reader that combines header and file content with context awareness.
|
// createStreamReaderWithContext creates a reader that combines header and file content with context awareness.
|
||||||
func (p *FileProcessor) createStreamReaderWithContext(ctx context.Context, filePath, relPath string) io.Reader {
|
func (p *FileProcessor) createStreamReaderWithContext(ctx context.Context, filePath, relPath string) io.Reader {
|
||||||
// Check context before opening file
|
// Check context before opening file
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package fileproc
|
package fileproc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -48,6 +49,12 @@ func (rm *ResourceMonitor) GetMetrics() ResourceMetrics {
|
|||||||
violations = append(violations, violation)
|
violations = append(violations, violation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Safe conversion: cap at MaxInt64 to prevent overflow
|
||||||
|
memoryUsage := int64(m.Alloc) / 1024 / 1024
|
||||||
|
if m.Alloc > math.MaxInt64 {
|
||||||
|
memoryUsage = math.MaxInt64 / 1024 / 1024
|
||||||
|
}
|
||||||
|
|
||||||
return ResourceMetrics{
|
return ResourceMetrics{
|
||||||
FilesProcessed: filesProcessed,
|
FilesProcessed: filesProcessed,
|
||||||
TotalSizeProcessed: totalSize,
|
TotalSizeProcessed: totalSize,
|
||||||
@@ -55,7 +62,7 @@ func (rm *ResourceMonitor) GetMetrics() ResourceMetrics {
|
|||||||
ProcessingDuration: duration,
|
ProcessingDuration: duration,
|
||||||
AverageFileSize: avgFileSize,
|
AverageFileSize: avgFileSize,
|
||||||
ProcessingRate: processingRate,
|
ProcessingRate: processingRate,
|
||||||
MemoryUsageMB: int64(m.Alloc) / 1024 / 1024,
|
MemoryUsageMB: memoryUsage,
|
||||||
MaxMemoryUsageMB: int64(rm.hardMemoryLimitMB),
|
MaxMemoryUsageMB: int64(rm.hardMemoryLimitMB),
|
||||||
ViolationsDetected: violations,
|
ViolationsDetected: violations,
|
||||||
DegradationActive: rm.degradationActive,
|
DegradationActive: rm.degradationActive,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package fileproc
|
package fileproc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -88,7 +89,11 @@ func (rm *ResourceMonitor) CheckHardMemoryLimit() error {
|
|||||||
|
|
||||||
var m runtime.MemStats
|
var m runtime.MemStats
|
||||||
runtime.ReadMemStats(&m)
|
runtime.ReadMemStats(&m)
|
||||||
|
// Safe conversion: cap at MaxInt64 to prevent overflow
|
||||||
currentMemory := int64(m.Alloc)
|
currentMemory := int64(m.Alloc)
|
||||||
|
if m.Alloc > math.MaxInt64 {
|
||||||
|
currentMemory = math.MaxInt64
|
||||||
|
}
|
||||||
|
|
||||||
if currentMemory > rm.hardMemoryLimitBytes {
|
if currentMemory > rm.hardMemoryLimitBytes {
|
||||||
rm.mu.Lock()
|
rm.mu.Lock()
|
||||||
@@ -108,7 +113,11 @@ func (rm *ResourceMonitor) CheckHardMemoryLimit() error {
|
|||||||
|
|
||||||
// Check again after GC
|
// Check again after GC
|
||||||
runtime.ReadMemStats(&m)
|
runtime.ReadMemStats(&m)
|
||||||
|
// Safe conversion: cap at MaxInt64 to prevent overflow
|
||||||
currentMemory = int64(m.Alloc)
|
currentMemory = int64(m.Alloc)
|
||||||
|
if m.Alloc > math.MaxInt64 {
|
||||||
|
currentMemory = math.MaxInt64
|
||||||
|
}
|
||||||
|
|
||||||
if currentMemory > rm.hardMemoryLimitBytes {
|
if currentMemory > rm.hardMemoryLimitBytes {
|
||||||
// Still over limit, activate emergency stop
|
// Still over limit, activate emergency stop
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -25,7 +25,6 @@ require (
|
|||||||
github.com/spf13/cast v1.10.0 // indirect
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
|
||||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
golang.org/x/term v0.28.0 // indirect
|
golang.org/x/term v0.28.0 // indirect
|
||||||
|
|||||||
28
go.sum
28
go.sum
@@ -7,12 +7,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
|||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
|
||||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
|
||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
|
||||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
@@ -30,8 +26,6 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
|
|||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@@ -42,45 +36,29 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV
|
|||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
|
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
|
||||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
|
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
|
||||||
github.com/sagikazarmark/locafero v0.8.0 h1:mXaMVw7IqxNBxfv3LdWt9MDmcWDQ1fagDH918lOdVaQ=
|
|
||||||
github.com/sagikazarmark/locafero v0.8.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
|
|
||||||
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||||
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
|
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
|
||||||
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
|
||||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
|
||||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||||
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
|
|
||||||
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
|
|
||||||
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
|
||||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
|
||||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
|
||||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY=
|
|
||||||
github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
|
||||||
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
|
||||||
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
|
||||||
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||||
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
|
||||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -90,8 +68,6 @@ golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
|||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
|
||||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -20,306 +20,306 @@ NC='\033[0m' # No Color
|
|||||||
|
|
||||||
# Function to print status
|
# Function to print status
|
||||||
print_status() {
|
print_status() {
|
||||||
echo -e "${BLUE}[INFO]${NC} $1"
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_warning() {
|
print_warning() {
|
||||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_error() {
|
print_error() {
|
||||||
echo -e "${RED}[ERROR]${NC} $1"
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_success() {
|
print_success() {
|
||||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check if required tools are installed
|
# Check if required tools are installed
|
||||||
check_dependencies() {
|
check_dependencies() {
|
||||||
print_status "Checking security scanning dependencies..."
|
print_status "Checking security scanning dependencies..."
|
||||||
|
|
||||||
local missing_tools=()
|
local missing_tools=()
|
||||||
|
|
||||||
if ! command -v go &>/dev/null; then
|
if ! command -v go &>/dev/null; then
|
||||||
missing_tools+=("go")
|
missing_tools+=("go")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v golangci-lint &>/dev/null; then
|
if ! command -v golangci-lint &>/dev/null; then
|
||||||
print_warning "golangci-lint not found, installing..."
|
print_warning "golangci-lint not found, installing..."
|
||||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v gosec &>/dev/null; then
|
if ! command -v gosec &>/dev/null; then
|
||||||
print_warning "gosec not found, installing..."
|
print_warning "gosec not found, installing..."
|
||||||
go install github.com/securecodewarrior/gosec/v2/cmd/gosec@latest
|
go install github.com/securecodewarrior/gosec/v2/cmd/gosec@latest
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v govulncheck &>/dev/null; then
|
if ! command -v govulncheck &>/dev/null; then
|
||||||
print_warning "govulncheck not found, installing..."
|
print_warning "govulncheck not found, installing..."
|
||||||
go install golang.org/x/vuln/cmd/govulncheck@latest
|
go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v checkmake &>/dev/null; then
|
if ! command -v checkmake &>/dev/null; then
|
||||||
print_warning "checkmake not found, installing..."
|
print_warning "checkmake not found, installing..."
|
||||||
go install github.com/mrtazz/checkmake/cmd/checkmake@latest
|
go install github.com/mrtazz/checkmake/cmd/checkmake@latest
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v shfmt &>/dev/null; then
|
if ! command -v shfmt &>/dev/null; then
|
||||||
print_warning "shfmt not found, installing..."
|
print_warning "shfmt not found, installing..."
|
||||||
go install mvdan.cc/sh/v3/cmd/shfmt@latest
|
go install mvdan.cc/sh/v3/cmd/shfmt@latest
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! command -v yamllint &>/dev/null; then
|
if ! command -v yamllint &>/dev/null; then
|
||||||
print_warning "yamllint not found, installing..."
|
print_warning "yamllint not found, installing..."
|
||||||
go install github.com/excilsploft/yamllint@latest
|
go install github.com/excilsploft/yamllint@latest
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ${#missing_tools[@]} -ne 0 ]; then
|
if [ ${#missing_tools[@]} -ne 0 ]; then
|
||||||
print_error "Missing required tools: ${missing_tools[*]}"
|
print_error "Missing required tools: ${missing_tools[*]}"
|
||||||
print_error "Please install the missing tools and try again."
|
print_error "Please install the missing tools and try again."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_success "All dependencies are available"
|
print_success "All dependencies are available"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run gosec security scanner
|
# Run gosec security scanner
|
||||||
run_gosec() {
|
run_gosec() {
|
||||||
print_status "Running gosec security scanner..."
|
print_status "Running gosec security scanner..."
|
||||||
|
|
||||||
if gosec -fmt=json -out=gosec-report.json -stdout -verbose=text ./...; then
|
if gosec -fmt=json -out=gosec-report.json -stdout -verbose=text ./...; then
|
||||||
print_success "gosec scan completed successfully"
|
print_success "gosec scan completed successfully"
|
||||||
else
|
else
|
||||||
print_error "gosec found security issues!"
|
print_error "gosec found security issues!"
|
||||||
if [ -f "gosec-report.json" ]; then
|
if [ -f "gosec-report.json" ]; then
|
||||||
echo "Detailed report saved to gosec-report.json"
|
echo "Detailed report saved to gosec-report.json"
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run vulnerability check
|
# Run vulnerability check
|
||||||
run_govulncheck() {
|
run_govulncheck() {
|
||||||
print_status "Running govulncheck for dependency vulnerabilities..."
|
print_status "Running govulncheck for dependency vulnerabilities..."
|
||||||
|
|
||||||
if govulncheck -json ./... >govulncheck-report.json 2>&1; then
|
if govulncheck -json ./... >govulncheck-report.json 2>&1; then
|
||||||
print_success "No known vulnerabilities found in dependencies"
|
print_success "No known vulnerabilities found in dependencies"
|
||||||
else
|
else
|
||||||
if grep -q '"finding"' govulncheck-report.json 2>/dev/null; then
|
if grep -q '"finding"' govulncheck-report.json 2>/dev/null; then
|
||||||
print_error "Vulnerabilities found in dependencies!"
|
print_error "Vulnerabilities found in dependencies!"
|
||||||
echo "Detailed report saved to govulncheck-report.json"
|
echo "Detailed report saved to govulncheck-report.json"
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
print_success "No vulnerabilities found"
|
print_success "No vulnerabilities found"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run enhanced golangci-lint with security focus
|
# Run enhanced golangci-lint with security focus
|
||||||
run_security_lint() {
|
run_security_lint() {
|
||||||
print_status "Running security-focused linting..."
|
print_status "Running security-focused linting..."
|
||||||
|
|
||||||
local security_linters="gosec,gocritic,bodyclose,rowserrcheck,misspell,unconvert,unparam,unused,errcheck,ineffassign,staticcheck"
|
local security_linters="gosec,gocritic,bodyclose,rowserrcheck,misspell,unconvert,unparam,unused,errcheck,ineffassign,staticcheck"
|
||||||
|
|
||||||
if golangci-lint run --enable="$security_linters" --timeout=5m; then
|
if golangci-lint run --enable="$security_linters" --timeout=5m; then
|
||||||
print_success "Security linting passed"
|
print_success "Security linting passed"
|
||||||
else
|
else
|
||||||
print_error "Security linting found issues!"
|
print_error "Security linting found issues!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check for potential secrets
|
# Check for potential secrets
|
||||||
check_secrets() {
|
check_secrets() {
|
||||||
print_status "Scanning for potential secrets and sensitive data..."
|
print_status "Scanning for potential secrets and sensitive data..."
|
||||||
|
|
||||||
local secrets_found=false
|
local secrets_found=false
|
||||||
|
|
||||||
# Common secret patterns
|
# Common secret patterns
|
||||||
local patterns=(
|
local patterns=(
|
||||||
"password\s*[:=]\s*['\"][^'\"]{3,}['\"]"
|
"password\s*[:=]\s*['\"][^'\"]{3,}['\"]"
|
||||||
"secret\s*[:=]\s*['\"][^'\"]{3,}['\"]"
|
"secret\s*[:=]\s*['\"][^'\"]{3,}['\"]"
|
||||||
"key\s*[:=]\s*['\"][^'\"]{8,}['\"]"
|
"key\s*[:=]\s*['\"][^'\"]{8,}['\"]"
|
||||||
"token\s*[:=]\s*['\"][^'\"]{8,}['\"]"
|
"token\s*[:=]\s*['\"][^'\"]{8,}['\"]"
|
||||||
"api_?key\s*[:=]\s*['\"][^'\"]{8,}['\"]"
|
"api_?key\s*[:=]\s*['\"][^'\"]{8,}['\"]"
|
||||||
"aws_?access_?key"
|
"aws_?access_?key"
|
||||||
"aws_?secret"
|
"aws_?secret"
|
||||||
"AKIA[0-9A-Z]{16}" # AWS Access Key pattern
|
"AKIA[0-9A-Z]{16}" # AWS Access Key pattern
|
||||||
"github_?token"
|
"github_?token"
|
||||||
"private_?key"
|
"private_?key"
|
||||||
)
|
)
|
||||||
|
|
||||||
for pattern in "${patterns[@]}"; do
|
for pattern in "${patterns[@]}"; do
|
||||||
if grep -r -i -E "$pattern" --include="*.go" . 2>/dev/null; then
|
if grep -r -i -E "$pattern" --include="*.go" . 2>/dev/null; then
|
||||||
print_warning "Potential secret pattern found: $pattern"
|
print_warning "Potential secret pattern found: $pattern"
|
||||||
secrets_found=true
|
secrets_found=true
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Check git history for secrets (last 10 commits)
|
# Check git history for secrets (last 10 commits)
|
||||||
if git log --oneline -10 | grep -i -E "(password|secret|key|token)" >/dev/null 2>&1; then
|
if git log --oneline -10 | grep -i -E "(password|secret|key|token)" >/dev/null 2>&1; then
|
||||||
print_warning "Potential secrets mentioned in recent commit messages"
|
print_warning "Potential secrets mentioned in recent commit messages"
|
||||||
secrets_found=true
|
secrets_found=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$secrets_found" = true ]; then
|
if [ "$secrets_found" = true ]; then
|
||||||
print_warning "Potential secrets detected. Please review manually."
|
print_warning "Potential secrets detected. Please review manually."
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
print_success "No obvious secrets detected"
|
print_success "No obvious secrets detected"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check for hardcoded network addresses
|
# Check for hardcoded network addresses
|
||||||
check_hardcoded_addresses() {
|
check_hardcoded_addresses() {
|
||||||
print_status "Checking for hardcoded network addresses..."
|
print_status "Checking for hardcoded network addresses..."
|
||||||
|
|
||||||
local addresses_found=false
|
local addresses_found=false
|
||||||
|
|
||||||
# Look for IP addresses (excluding common safe ones)
|
# Look for IP addresses (excluding common safe ones)
|
||||||
if grep -r -E "([0-9]{1,3}\.){3}[0-9]{1,3}" --include="*.go" . |
|
if grep -r -E "([0-9]{1,3}\.){3}[0-9]{1,3}" --include="*.go" . |
|
||||||
grep -v -E "(127\.0\.0\.1|0\.0\.0\.0|255\.255\.255\.255|localhost)" >/dev/null 2>&1; then
|
grep -v -E "(127\.0\.0\.1|0\.0\.0\.0|255\.255\.255\.255|localhost)" >/dev/null 2>&1; then
|
||||||
print_warning "Hardcoded IP addresses found:"
|
print_warning "Hardcoded IP addresses found:"
|
||||||
grep -r -E "([0-9]{1,3}\.){3}[0-9]{1,3}" --include="*.go" . |
|
grep -r -E "([0-9]{1,3}\.){3}[0-9]{1,3}" --include="*.go" . |
|
||||||
grep -v -E "(127\.0\.0\.1|0\.0\.0\.0|255\.255\.255\.255|localhost)" || true
|
grep -v -E "(127\.0\.0\.1|0\.0\.0\.0|255\.255\.255\.255|localhost)" || true
|
||||||
addresses_found=true
|
addresses_found=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Look for URLs (excluding documentation examples)
|
# Look for URLs (excluding documentation examples)
|
||||||
if grep -r -E "https?://[^/\s]+" --include="*.go" . |
|
if grep -r -E "https?://[^/\s]+" --include="*.go" . |
|
||||||
grep -v -E "(example\.com|localhost|127\.0\.0\.1|\$\{)" >/dev/null 2>&1; then
|
grep -v -E "(example\.com|localhost|127\.0\.0\.1|\$\{)" >/dev/null 2>&1; then
|
||||||
print_warning "Hardcoded URLs found:"
|
print_warning "Hardcoded URLs found:"
|
||||||
grep -r -E "https?://[^/\s]+" --include="*.go" . |
|
grep -r -E "https?://[^/\s]+" --include="*.go" . |
|
||||||
grep -v -E "(example\.com|localhost|127\.0\.0\.1|\$\{)" || true
|
grep -v -E "(example\.com|localhost|127\.0\.0\.1|\$\{)" || true
|
||||||
addresses_found=true
|
addresses_found=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$addresses_found" = true ]; then
|
if [ "$addresses_found" = true ]; then
|
||||||
print_warning "Hardcoded network addresses detected. Please review."
|
print_warning "Hardcoded network addresses detected. Please review."
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
print_success "No hardcoded network addresses found"
|
print_success "No hardcoded network addresses found"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check Docker security (if Dockerfile exists)
|
# Check Docker security (if Dockerfile exists)
|
||||||
check_docker_security() {
|
check_docker_security() {
|
||||||
if [ -f "Dockerfile" ]; then
|
if [ -f "Dockerfile" ]; then
|
||||||
print_status "Checking Docker security..."
|
print_status "Checking Docker security..."
|
||||||
|
|
||||||
# Basic Dockerfile security checks
|
# Basic Dockerfile security checks
|
||||||
local docker_issues=false
|
local docker_issues=false
|
||||||
|
|
||||||
if grep -q "^USER root" Dockerfile; then
|
if grep -q "^USER root" Dockerfile; then
|
||||||
print_warning "Dockerfile runs as root user"
|
print_warning "Dockerfile runs as root user"
|
||||||
docker_issues=true
|
docker_issues=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! grep -q "^USER " Dockerfile; then
|
if ! grep -q "^USER " Dockerfile; then
|
||||||
print_warning "Dockerfile doesn't specify a non-root user"
|
print_warning "Dockerfile doesn't specify a non-root user"
|
||||||
docker_issues=true
|
docker_issues=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if grep -q "RUN.*wget\|RUN.*curl" Dockerfile && ! grep -q "rm.*wget\|rm.*curl" Dockerfile; then
|
if grep -q "RUN.*wget\|RUN.*curl" Dockerfile && ! grep -q "rm.*wget\|rm.*curl" Dockerfile; then
|
||||||
print_warning "Dockerfile may leave curl/wget installed"
|
print_warning "Dockerfile may leave curl/wget installed"
|
||||||
docker_issues=true
|
docker_issues=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$docker_issues" = true ]; then
|
if [ "$docker_issues" = true ]; then
|
||||||
print_warning "Docker security issues detected"
|
print_warning "Docker security issues detected"
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
print_success "Docker security check passed"
|
print_success "Docker security check passed"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
print_status "No Dockerfile found, skipping Docker security check"
|
print_status "No Dockerfile found, skipping Docker security check"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check file permissions
|
# Check file permissions
|
||||||
check_file_permissions() {
|
check_file_permissions() {
|
||||||
print_status "Checking file permissions..."
|
print_status "Checking file permissions..."
|
||||||
|
|
||||||
local perm_issues=false
|
local perm_issues=false
|
||||||
|
|
||||||
# Check for overly permissive files
|
# Check for overly permissive files
|
||||||
if find . -type f -perm /o+w -not -path "./.git/*" | grep -q .; then
|
if find . -type f -perm /o+w -not -path "./.git/*" | grep -q .; then
|
||||||
print_warning "World-writable files found:"
|
print_warning "World-writable files found:"
|
||||||
find . -type f -perm /o+w -not -path "./.git/*" || true
|
find . -type f -perm /o+w -not -path "./.git/*" || true
|
||||||
perm_issues=true
|
perm_issues=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check for executable files that shouldn't be
|
# Check for executable files that shouldn't be
|
||||||
if find . -type f -name "*.go" -perm /a+x | grep -q .; then
|
if find . -type f -name "*.go" -perm /a+x | grep -q .; then
|
||||||
print_warning "Executable Go files found (should not be executable):"
|
print_warning "Executable Go files found (should not be executable):"
|
||||||
find . -type f -name "*.go" -perm /a+x || true
|
find . -type f -name "*.go" -perm /a+x || true
|
||||||
perm_issues=true
|
perm_issues=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$perm_issues" = true ]; then
|
if [ "$perm_issues" = true ]; then
|
||||||
print_warning "File permission issues detected"
|
print_warning "File permission issues detected"
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
print_success "File permissions check passed"
|
print_success "File permissions check passed"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check Makefile with checkmake
|
# Check Makefile with checkmake
|
||||||
check_makefile() {
|
check_makefile() {
|
||||||
if [ -f "Makefile" ]; then
|
if [ -f "Makefile" ]; then
|
||||||
print_status "Checking Makefile with checkmake..."
|
print_status "Checking Makefile with checkmake..."
|
||||||
|
|
||||||
if checkmake --config=.checkmake Makefile; then
|
if checkmake --config=.checkmake Makefile; then
|
||||||
print_success "Makefile check passed"
|
print_success "Makefile check passed"
|
||||||
else
|
else
|
||||||
print_error "Makefile issues detected!"
|
print_error "Makefile issues detected!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
print_status "No Makefile found, skipping checkmake"
|
print_status "No Makefile found, skipping checkmake"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check shell scripts with shfmt
|
# Check shell scripts with shfmt
|
||||||
check_shell_scripts() {
|
check_shell_scripts() {
|
||||||
print_status "Checking shell script formatting..."
|
print_status "Checking shell script formatting..."
|
||||||
|
|
||||||
if find . -name "*.sh" -type f | head -1 | grep -q .; then
|
if find . -name "*.sh" -type f | head -1 | grep -q .; then
|
||||||
if shfmt -d .; then
|
if shfmt -d .; then
|
||||||
print_success "Shell script formatting check passed"
|
print_success "Shell script formatting check passed"
|
||||||
else
|
else
|
||||||
print_error "Shell script formatting issues detected!"
|
print_error "Shell script formatting issues detected!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
print_status "No shell scripts found, skipping shfmt check"
|
print_status "No shell scripts found, skipping shfmt check"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check YAML files
|
# Check YAML files
|
||||||
check_yaml_files() {
|
check_yaml_files() {
|
||||||
print_status "Checking YAML files..."
|
print_status "Checking YAML files..."
|
||||||
|
|
||||||
if find . -name "*.yml" -o -name "*.yaml" -type f | head -1 | grep -q .; then
|
if find . -name "*.yml" -o -name "*.yaml" -type f | head -1 | grep -q .; then
|
||||||
if yamllint -c .yamllint .; then
|
if yamllint -c .yamllint .; then
|
||||||
print_success "YAML files check passed"
|
print_success "YAML files check passed"
|
||||||
else
|
else
|
||||||
print_error "YAML file issues detected!"
|
print_error "YAML file issues detected!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
print_status "No YAML files found, skipping yamllint check"
|
print_status "No YAML files found, skipping yamllint check"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Generate security report
|
# Generate security report
|
||||||
generate_report() {
|
generate_report() {
|
||||||
print_status "Generating security scan report..."
|
print_status "Generating security scan report..."
|
||||||
|
|
||||||
local report_file="security-report.md"
|
local report_file="security-report.md"
|
||||||
|
|
||||||
cat >"$report_file" <<EOF
|
cat >"$report_file" <<EOF
|
||||||
# Security Scan Report
|
# Security Scan Report
|
||||||
|
|
||||||
**Generated:** $(date)
|
**Generated:** $(date)
|
||||||
@@ -361,65 +361,65 @@ generate_report() {
|
|||||||
*This report was generated automatically by the gibidify security scanning script.*
|
*This report was generated automatically by the gibidify security scanning script.*
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
print_success "Security report generated: $report_file"
|
print_success "Security report generated: $report_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main execution
|
# Main execution
|
||||||
main() {
|
main() {
|
||||||
echo "🔒 gibidify Security Scanner"
|
echo "🔒 gibidify Security Scanner"
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
echo
|
echo
|
||||||
|
|
||||||
local exit_code=0
|
local exit_code=0
|
||||||
|
|
||||||
check_dependencies
|
check_dependencies
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Run all security checks
|
# Run all security checks
|
||||||
run_gosec || exit_code=1
|
run_gosec || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
run_govulncheck || exit_code=1
|
run_govulncheck || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
run_security_lint || exit_code=1
|
run_security_lint || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
check_secrets || exit_code=1
|
check_secrets || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
check_hardcoded_addresses || exit_code=1
|
check_hardcoded_addresses || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
check_docker_security || exit_code=1
|
check_docker_security || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
check_file_permissions || exit_code=1
|
check_file_permissions || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
check_makefile || exit_code=1
|
check_makefile || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
check_shell_scripts || exit_code=1
|
check_shell_scripts || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
check_yaml_files || exit_code=1
|
check_yaml_files || exit_code=1
|
||||||
echo
|
echo
|
||||||
|
|
||||||
generate_report
|
generate_report
|
||||||
echo
|
echo
|
||||||
|
|
||||||
if [ $exit_code -eq 0 ]; then
|
if [ $exit_code -eq 0 ]; then
|
||||||
print_success "🎉 All security checks passed!"
|
print_success "🎉 All security checks passed!"
|
||||||
else
|
else
|
||||||
print_error "❌ Security issues detected. Please review the reports and fix identified issues."
|
print_error "❌ Security issues detected. Please review the reports and fix identified issues."
|
||||||
print_status "Generated reports:"
|
print_status "Generated reports:"
|
||||||
print_status "- gosec-report.json (if exists)"
|
print_status "- gosec-report.json (if exists)"
|
||||||
print_status "- govulncheck-report.json (if exists)"
|
print_status "- govulncheck-report.json (if exists)"
|
||||||
print_status "- security-report.md"
|
print_status "- security-report.md"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit $exit_code
|
exit $exit_code
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run main function
|
# Run main function
|
||||||
|
|||||||
Reference in New Issue
Block a user