Cybersecurity-Projects/PROJECTS/intermediate/secrets-scanner/internal/reporter/reporter_test.go

216 lines
5.3 KiB
Go

// ©AngelaMos | 2026
// reporter_test.go
package reporter
import (
"bytes"
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/CarterPerez-dev/portia/pkg/types"
)
func testResult() *types.ScanResult {
return &types.ScanResult{
Findings: []types.Finding{
{ //nolint:gosec
RuleID: "aws-access-key-id",
Description: "AWS Access Key ID",
Severity: types.SeverityCritical,
Match: `AKIAIOSFODNN7EXAMPLE`,
Secret: "AKIAIOSFODNN7EXAMPLE",
FilePath: "src/config.py",
LineNumber: 42,
LineContent: `aws_key = "AKIAIOSFODNN7EXAMPLE"`,
CommitSHA: "abc123def456",
Author: "dev@example.com",
HIBPStatus: types.HIBPBreached,
BreachCount: 1500,
},
{ //nolint:gosec
RuleID: "generic-password",
Description: "Password in Assignment",
Severity: types.SeverityHigh,
Match: `password = "xK9mP2vL5nQ8"`,
Secret: "xK9mP2vL5nQ8",
Entropy: 4.12,
FilePath: "config.yaml",
LineNumber: 10,
LineContent: `password = "xK9mP2vL5nQ8"`,
HIBPStatus: types.HIBPClean,
},
},
TotalFiles: 100,
TotalRules: 50,
TotalFindings: 2,
HIBPChecked: 2,
HIBPBreached: 1,
Duration: 1500 * time.Millisecond,
}
}
func TestNewReporter(t *testing.T) {
t.Parallel()
assert.IsType(t, &Terminal{}, New("terminal"))
assert.IsType(t, &Terminal{}, New(""))
assert.IsType(t, &JSON{}, New("json"))
assert.IsType(t, &SARIF{}, New("sarif"))
}
func TestTerminalReportWithFindings(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
r := &Terminal{}
err := r.Report(&buf, testResult())
require.NoError(t, err)
output := buf.String()
assert.Contains(t, output, "2 secret(s) detected")
assert.Contains(t, output, "aws-access-key-id")
assert.Contains(t, output, "src/config.py")
assert.Contains(t, output, "FOUND IN BREACHES")
assert.Contains(t, output, "not found in breaches")
assert.Contains(t, output, "4.12")
assert.Contains(t, output, "abc123de")
}
func TestTerminalReportNoFindings(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
r := &Terminal{}
result := &types.ScanResult{
TotalRules: 50,
Duration: 500 * time.Millisecond,
}
err := r.Report(&buf, result)
require.NoError(t, err)
output := buf.String()
assert.Contains(t, output, "No secrets detected")
}
func TestJSONReport(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
r := &JSON{}
err := r.Report(&buf, testResult())
require.NoError(t, err)
var output jsonOutput
require.NoError(t, json.Unmarshal(buf.Bytes(), &output))
assert.Len(t, output.Findings, 2)
assert.Equal(t, "aws-access-key-id", output.Findings[0].RuleID)
assert.Equal(t, "CRITICAL", output.Findings[0].Severity)
assert.NotContains(t, output.Findings[0].Secret, "AKIAIOSFODNN7EXAMPLE")
assert.Equal(t, 100, output.Summary.TotalFiles)
assert.Equal(t, 2, output.Summary.TotalFindings)
assert.Equal(t, 50, output.Summary.TotalRules)
}
func TestJSONReportNoFindings(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
r := &JSON{}
result := &types.ScanResult{TotalRules: 50}
err := r.Report(&buf, result)
require.NoError(t, err)
var output jsonOutput
require.NoError(t, json.Unmarshal(buf.Bytes(), &output))
assert.Empty(t, output.Findings)
}
func TestSARIFReport(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
r := &SARIF{}
err := r.Report(&buf, testResult())
require.NoError(t, err)
var log sarifLog
require.NoError(t, json.Unmarshal(buf.Bytes(), &log))
assert.Equal(t, "2.1.0", log.Version)
require.Len(t, log.Runs, 1)
run := log.Runs[0]
assert.Equal(t, "portia", run.Tool.Driver.Name)
assert.Len(t, run.Results, 2)
assert.Equal(t, "aws-access-key-id", run.Results[0].RuleID)
assert.Equal(t, "error", run.Results[0].Level)
assert.Equal(t,
"src/config.py",
run.Results[0].Locations[0].PhysicalLocation.
ArtifactLocation.URI,
)
assert.Equal(t,
42,
run.Results[0].Locations[0].PhysicalLocation.Region.StartLine,
)
}
func TestSARIFReportNoFindings(t *testing.T) {
t.Parallel()
var buf bytes.Buffer
r := &SARIF{}
result := &types.ScanResult{TotalRules: 50}
err := r.Report(&buf, result)
require.NoError(t, err)
var log sarifLog
require.NoError(t, json.Unmarshal(buf.Bytes(), &log))
assert.Empty(t, log.Runs[0].Results)
}
func TestMaskSecret(t *testing.T) {
t.Parallel()
tests := map[string]struct {
input string
want string
}{
"short secret": {
input: "abc",
want: "***",
},
"medium secret": {
input: "AKIAIOSFODNN7EXA",
want: "AKIA********7EXA",
},
"long secret": { //nolint:gosec
input: "sk_live_4eC39HqLyjWDarjtT1zdp7dc",
want: "sk_liv********************zdp7dc",
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
t.Parallel()
got := maskSecret(tc.input)
assert.Equal(t, tc.want, got)
})
}
}
func TestTruncateSHA(t *testing.T) {
t.Parallel()
assert.Equal(t, "abc123de", truncateSHA("abc123def456"))
assert.Equal(t, "short", truncateSHA("short"))
}
func TestSeverityToSARIF(t *testing.T) {
t.Parallel()
assert.Equal(t, "error", severityToSARIF(types.SeverityCritical))
assert.Equal(t, "error", severityToSARIF(types.SeverityHigh))
assert.Equal(t, "warning", severityToSARIF(types.SeverityMedium))
assert.Equal(t, "note", severityToSARIF(types.SeverityLow))
}