Function bodies 513 total
output.severityToLevel function · go · L107-L116 (10 LOC)internal/security/output/sarif.go
func severityToLevel(s security.Severity) string {
switch s {
case security.SeverityCritical, security.SeverityHigh:
return "error"
case security.SeverityMedium:
return "warning"
default:
return "note"
}
}output.buildRules function · go · L119-L135 (17 LOC)internal/security/output/sarif.go
func buildRules(findings []security.Finding) []sarifRule {
seen := make(map[string]bool)
var rules []sarifRule
for _, f := range findings {
if f.CWE == "" || seen[f.CWE] {
continue
}
seen[f.CWE] = true
rules = append(rules, sarifRule{
ID: f.CWE,
ShortDescription: sarifMessageStr{Text: f.Title},
})
}
return rules
}output.buildResults function · go · L138-L162 (25 LOC)internal/security/output/sarif.go
func buildResults(findings []security.Finding) []sarifResult {
results := make([]sarifResult, 0, len(findings))
for _, f := range findings {
result := sarifResult{
RuleID: f.CWE,
Level: severityToLevel(f.Severity),
Message: sarifMessageStr{Text: f.Title},
Locations: []sarifLocation{
{
PhysicalLocation: sarifPhysicalLocation{
ArtifactLocation: sarifArtifactLocation{URI: f.Location.File},
Region: sarifRegion{
StartLine: f.Location.StartLine,
EndLine: f.Location.EndLine,
},
},
},
},
}
results = append(results, result)
}
return results
}output.WikiFormatter.Format method · go · L32-L40 (9 LOC)internal/security/output/wiki.go
func (f *WikiFormatter) Format(report *security.Report) ([]byte, error) {
wiki := WikiOutput{
Overview: buildOverviewPage(report),
Findings: buildFindingsPage(report),
AttackChains: buildAttackChainsPage(report),
}
return json.MarshalIndent(wiki, "", " ")
}output.buildOverviewPage function · go · L43-L67 (25 LOC)internal/security/output/wiki.go
func buildOverviewPage(report *security.Report) string {
summary := report.Summary()
var b strings.Builder
b.WriteString("# Security Overview\n\n")
b.WriteString("## Scan Statistics\n\n")
b.WriteString(fmt.Sprintf("- **Duration:** %dms\n", report.Stats.Duration.Milliseconds()))
b.WriteString(fmt.Sprintf("- **Files scanned:** %d\n", report.Stats.FilesScanned))
b.WriteString(fmt.Sprintf("- **Chunks analyzed:** %d\n", report.Stats.ChunksAnalyzed))
b.WriteString("\n")
b.WriteString("## Findings Summary\n\n")
b.WriteString("| Severity | Count |\n")
b.WriteString("|----------|-------|\n")
b.WriteString(fmt.Sprintf("| Critical | %d |\n", summary.Critical))
b.WriteString(fmt.Sprintf("| High | %d |\n", summary.High))
b.WriteString(fmt.Sprintf("| Medium | %d |\n", summary.Medium))
b.WriteString(fmt.Sprintf("| Low | %d |\n", summary.Low))
b.WriteString(fmt.Sprintf("| Info | %d |\n", summary.Info))
b.WriteString(fmt.Sprintf("| **Total** | **%d** |\n", summary.Total))
b.WriteStroutput.buildFindingsPage function · go · L70-L119 (50 LOC)internal/security/output/wiki.go
func buildFindingsPage(report *security.Report) string {
var b strings.Builder
b.WriteString("# Security Findings\n\n")
if len(report.Findings) == 0 {
b.WriteString("No findings detected.\n")
return b.String()
}
// Group by category
byCategory := make(map[security.Category][]security.Finding)
var categoryOrder []security.Category
for _, f := range report.Findings {
if _, exists := byCategory[f.Category]; !exists {
categoryOrder = append(categoryOrder, f.Category)
}
byCategory[f.Category] = append(byCategory[f.Category], f)
}
for _, cat := range categoryOrder {
findings := byCategory[cat]
b.WriteString(fmt.Sprintf("## %s\n\n", string(cat)))
for _, f := range findings {
b.WriteString(fmt.Sprintf("### [%s] %s\n\n", f.ID, f.Title))
b.WriteString(fmt.Sprintf("- **Severity:** %s\n", string(f.Severity)))
b.WriteString(fmt.Sprintf("- **Confidence:** %s\n", string(f.Confidence)))
loc := fmt.Sprintf("%s:%d", f.Location.File, f.Location.StartLine)
ioutput.buildAttackChainsPage function · go · L122-L151 (30 LOC)internal/security/output/wiki.go
func buildAttackChainsPage(report *security.Report) string {
var b strings.Builder
b.WriteString("# Attack Chains\n\n")
if len(report.AttackChains) == 0 {
b.WriteString("No attack chains detected.\n")
return b.String()
}
for _, chain := range report.AttackChains {
b.WriteString(fmt.Sprintf("## [%s] %s\n\n", chain.ID, chain.Title))
b.WriteString(fmt.Sprintf("- **Severity:** %s\n", string(chain.Severity)))
if chain.Impact != "" {
b.WriteString(fmt.Sprintf("- **Impact:** %s\n", chain.Impact))
}
if chain.Likelihood != "" {
b.WriteString(fmt.Sprintf("- **Likelihood:** %s\n", chain.Likelihood))
}
if len(chain.Steps) > 0 {
b.WriteString("\n### Steps\n\n")
for i, step := range chain.Steps {
b.WriteString(fmt.Sprintf("%d. [%s] %s\n", i+1, step.ID, step.Title))
}
}
b.WriteString("\n")
}
return b.String()
}Repobility · code-quality intelligence · https://repobility.com
security.Prioritizer.Prioritize method · go · L59-L102 (44 LOC)internal/security/prioritizer.go
func (p *Prioritizer) Prioritize(ctx context.Context, target ScanTarget, staticFindings []Finding) ([]AnalysisChunk, error) {
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("prioritizer cancelled: %w", err)
}
files, err := CollectFiles(target, nil)
if err != nil {
return nil, fmt.Errorf("collecting files: %w", err)
}
flaggedFiles := buildFlaggedFileSet(staticFindings)
codeParser := parser.NewParser()
var chunks []AnalysisChunk
for _, relPath := range files {
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("prioritizer cancelled: %w", err)
}
absPath := filepath.Join(target.RootDir, relPath)
data, err := os.ReadFile(absPath)
if err != nil {
continue // skip unreadable files
}
score := p.scoreFile(string(data))
if flaggedFiles[relPath] {
score += staticFindingBoost
}
language := extensionToLanguage(relPath)
fileChunks := p.splitIntoChunks(codeParser, relPath, data, score, language)
chunks = append(chunks, fileChunks...security.Prioritizer.scoreFile method · go · L105-L113 (9 LOC)internal/security/prioritizer.go
func (p *Prioritizer) scoreFile(content string) int {
score := 0
for _, signal := range riskSignals {
if signal.pattern.MatchString(content) {
score += signal.score
}
}
return score
}security.Prioritizer.splitIntoChunks method · go · L117-L152 (36 LOC)internal/security/prioritizer.go
func (p *Prioritizer) splitIntoChunks(codeParser *parser.Parser, relPath string, data []byte, score int, language string) []AnalysisChunk {
tree, err := codeParser.Parse(relPath, data)
if err != nil {
return []AnalysisChunk{p.wholeFileChunk(relPath, data, score, language)}
}
defer tree.Close()
funcs := tree.Functions()
if len(funcs) == 0 {
return []AnalysisChunk{p.wholeFileChunk(relPath, data, score, language)}
}
lines := strings.Split(string(data), "\n")
var chunks []AnalysisChunk
for _, fn := range funcs {
start := fn.StartLine
end := fn.EndLine
if start < 1 {
start = 1
}
if end > len(lines) {
end = len(lines)
}
content := strings.Join(lines[start-1:end], "\n")
chunks = append(chunks, AnalysisChunk{
File: relPath,
StartLine: start,
EndLine: end,
Content: content,
Language: language,
RiskScore: score,
})
}
return chunks
}security.Prioritizer.wholeFileChunk method · go · L155-L165 (11 LOC)internal/security/prioritizer.go
func (p *Prioritizer) wholeFileChunk(relPath string, data []byte, score int, language string) AnalysisChunk {
lineCount := strings.Count(string(data), "\n") + 1
return AnalysisChunk{
File: relPath,
StartLine: 1,
EndLine: lineCount,
Content: string(data),
Language: language,
RiskScore: score,
}
}security.Prioritizer.filterByMinScore method · go · L168-L179 (12 LOC)internal/security/prioritizer.go
func (p *Prioritizer) filterByMinScore(chunks []AnalysisChunk) []AnalysisChunk {
if p.config.MinRiskScore <= 0 {
return chunks
}
var filtered []AnalysisChunk
for _, c := range chunks {
if c.RiskScore >= p.config.MinRiskScore {
filtered = append(filtered, c)
}
}
return filtered
}security.Prioritizer.capChunks method · go · L182-L187 (6 LOC)internal/security/prioritizer.go
func (p *Prioritizer) capChunks(chunks []AnalysisChunk) []AnalysisChunk {
if p.config.MaxChunks > 0 && len(chunks) > p.config.MaxChunks {
return chunks[:p.config.MaxChunks]
}
return chunks
}security.buildFlaggedFileSet function · go · L190-L198 (9 LOC)internal/security/prioritizer.go
func buildFlaggedFileSet(findings []Finding) map[string]bool {
flagged := make(map[string]bool, len(findings))
for _, f := range findings {
if f.Location.File != "" {
flagged[f.Location.File] = true
}
}
return flagged
}security.extensionToLanguage function · go · L201-L229 (29 LOC)internal/security/prioritizer.go
func extensionToLanguage(path string) string {
ext := filepath.Ext(path)
switch ext {
case ".go":
return "go"
case ".py":
return "python"
case ".js":
return "javascript"
case ".ts":
return "typescript"
case ".tsx":
return "typescript"
case ".jsx":
return "javascript"
case ".java":
return "java"
case ".rs":
return "rust"
case ".rb":
return "ruby"
case ".c", ".h":
return "c"
case ".cc", ".cpp":
return "cpp"
default:
return ""
}
}Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
security.LoadProjectConfig function · go · L42-L76 (35 LOC)internal/security/projectconfig.go
func LoadProjectConfig(dir string) (*ProjectSecurityConfig, error) {
data, err := os.ReadFile(filepath.Join(dir, ".security.yaml"))
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("reading .security.yaml: %w", err)
}
if strings.TrimSpace(string(data)) == "" {
return nil, nil
}
var cfg ProjectSecurityConfig
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parsing .security.yaml: %w", err)
}
// Validate severity strings against known values.
for i, r := range cfg.Rules {
if r.Severity != "" && SeverityRank(Severity(r.Severity)) == 0 {
return nil, fmt.Errorf(".security.yaml: rule %q has invalid severity %q (must be critical, high, medium, low, or info)", r.ID, r.Severity)
}
if r.ID == "" {
return nil, fmt.Errorf(".security.yaml: rule at index %d is missing required id field", i)
}
}
for _, o := range cfg.Overrides {
if o.Severity != "" && SeverityRank(Severity(o.Severity)) == 0 {
retusecurity.ApplyOverrides function · go · L80-L97 (18 LOC)internal/security/projectconfig.go
func ApplyOverrides(findings []Finding, overrides []Override) int {
if len(findings) == 0 || len(overrides) == 0 {
return 0
}
overrideMap := make(map[string]Override, len(overrides))
for _, o := range overrides {
overrideMap[o.FindingID] = o
}
count := 0
for i := range findings {
if o, ok := overrideMap[findings[i].ID]; ok {
findings[i].Severity = Severity(o.Severity)
count++
}
}
return count
}scanner.AppleScanner.Scan method · go · L35-L95 (61 LOC)internal/security/scanner/apple.go
func (s *AppleScanner) Scan(ctx context.Context, target security.ScanTarget) ([]security.Finding, error) {
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("apple scanner cancelled: %w", err)
}
files, err := s.collectFiles(target)
if err != nil {
return nil, fmt.Errorf("collecting files: %w", err)
}
var findings []security.Finding
var plistFiles []string
var entitlementFiles []string
var swiftFiles []string
for _, relPath := range files {
base := filepath.Base(relPath)
ext := filepath.Ext(relPath)
switch {
case base == "Info.plist" || strings.HasSuffix(relPath, "Info.plist"):
plistFiles = append(plistFiles, relPath)
case ext == ".entitlements":
entitlementFiles = append(entitlementFiles, relPath)
case ext == ".swift":
swiftFiles = append(swiftFiles, relPath)
}
}
// No Apple files found at all: return empty.
if len(plistFiles) == 0 && len(entitlementFiles) == 0 && len(swiftFiles) == 0 {
return nil, nil
}
for _, relPath := range scanner.AppleScanner.checkPlist method · go · L111-L139 (29 LOC)internal/security/scanner/apple.go
func (s *AppleScanner) checkPlist(absPath, relPath string) []security.Finding {
data, err := os.ReadFile(absPath)
if err != nil {
return nil
}
dict, err := parsePlistXML(data)
if err != nil {
return nil
}
var findings []security.Finding
// Check for ATS bypass: NSAllowsArbitraryLoads = true
for i, key := range dict.Keys {
if key == "NSAllowsArbitraryLoads" && i < len(dict.Values) && dict.Values[i] == "true" {
findings = append(findings, s.newFinding(
"App Transport Security bypass enabled",
"NSAllowsArbitraryLoads is set to true, which disables ATS and allows insecure HTTP connections",
security.SeverityHigh,
security.CategoryMisconfiguration,
"",
relPath,
))
}
}
return findings
}scanner.parsePlistXML function · go · L143-L211 (69 LOC)internal/security/scanner/apple.go
func parsePlistXML(data []byte) (*plistDict, error) {
decoder := xml.NewDecoder(strings.NewReader(string(data)))
decoder.Strict = false
dict := &plistDict{}
var inDict bool
var expectValue bool
var currentKey string
for {
tok, err := decoder.Token()
if err != nil {
break
}
switch t := tok.(type) {
case xml.StartElement:
switch t.Name.Local {
case "dict":
inDict = true
case "key":
if inDict {
var key string
if err := decoder.DecodeElement(&key, &t); err == nil {
currentKey = key
expectValue = true
}
}
case "true":
if expectValue {
dict.Keys = append(dict.Keys, currentKey)
dict.Values = append(dict.Values, "true")
expectValue = false
}
case "false":
if expectValue {
dict.Keys = append(dict.Keys, currentKey)
dict.Values = append(dict.Values, "false")
expectValue = false
}
case "string":
if expectValue {
var val string
if err := decoder.DecodeElement(&scanner.AppleScanner.checkEntitlements method · go · L230-L260 (31 LOC)internal/security/scanner/apple.go
func (s *AppleScanner) checkEntitlements(absPath, relPath string) []security.Finding {
data, err := os.ReadFile(absPath)
if err != nil {
return nil
}
dict, err := parsePlistXML(data)
if err != nil {
return nil
}
var findings []security.Finding
for i, key := range dict.Keys {
ent, ok := dangerousEntitlements[key]
if !ok {
continue
}
if i < len(dict.Values) && dict.Values[i] == "true" {
findings = append(findings, s.newFinding(
ent.title,
fmt.Sprintf("Entitlement %s is enabled", key),
ent.severity,
security.CategoryMisconfiguration,
"",
relPath,
))
}
}
return findings
}scanner.AppleScanner.checkSwiftFile method · go · L268-L289 (22 LOC)internal/security/scanner/apple.go
func (s *AppleScanner) checkSwiftFile(absPath, relPath string) []security.Finding {
data, err := os.ReadFile(absPath)
if err != nil {
return nil
}
var findings []security.Finding
content := string(data)
if userDefaultsSensitivePat.MatchString(content) {
findings = append(findings, s.newFinding(
"Sensitive data stored in UserDefaults",
"UserDefaults is not encrypted; use Keychain for sensitive data like passwords and tokens",
security.SeverityMedium,
security.CategoryDataExposure,
"",
relPath,
))
}
return findings
}scanner.AppleScanner.newFinding method · go · L293-L312 (20 LOC)internal/security/scanner/apple.go
func (s *AppleScanner) newFinding(title, description string, severity security.Severity, category security.Category, cwe, file string) security.Finding {
s.mu.Lock()
s.findingCounter++
id := fmt.Sprintf("APPLE-%04d", s.findingCounter)
s.mu.Unlock()
return security.Finding{
ID: id,
Scanner: "apple-platform",
Severity: severity,
Category: category,
Title: title,
Description: description,
Location: security.Location{
File: file,
},
CWE: cwe,
Confidence: security.ConfidenceHigh,
}
}Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
scanner.ConfigScanner.Scan method · go · L35-L57 (23 LOC)internal/security/scanner/config.go
func (s *ConfigScanner) Scan(ctx context.Context, target security.ScanTarget) ([]security.Finding, error) {
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("config scanner cancelled: %w", err)
}
files, err := security.CollectFiles(target, nil)
if err != nil {
return nil, fmt.Errorf("collecting files: %w", err)
}
var findings []security.Finding
for _, relPath := range files {
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("config scanner cancelled: %w", err)
}
absPath := filepath.Join(target.RootDir, relPath)
fileFindings := s.scanFile(absPath, relPath)
findings = append(findings, fileFindings...)
}
return findings, nil
}scanner.ConfigScanner.scanFile method · go · L60-L91 (32 LOC)internal/security/scanner/config.go
func (s *ConfigScanner) scanFile(absPath, relPath string) []security.Finding {
data, err := os.ReadFile(absPath)
if err != nil {
return nil
}
var findings []security.Finding
baseName := filepath.Base(relPath)
// Dockerfile checks
if strings.HasPrefix(baseName, "Dockerfile") {
findings = append(findings, s.checkDockerfile(data, relPath)...)
}
// Kubernetes YAML checks
if isKubernetesYAML(data, relPath) {
findings = append(findings, s.checkKubernetes(data, relPath)...)
}
// CI config checks
if isCIConfig(relPath) {
findings = append(findings, s.checkCIConfig(data, relPath)...)
}
// General config checks (YAML, TOML, env, JSON, properties, INI)
if isConfigFile(relPath) {
findings = append(findings, s.checkGeneralConfig(data, relPath)...)
}
return findings
}scanner.ConfigScanner.checkDockerfile method · go · L101-L142 (42 LOC)internal/security/scanner/config.go
func (s *ConfigScanner) checkDockerfile(data []byte, relPath string) []security.Finding {
var findings []security.Finding
content := string(data)
// Check for USER root
if dockerUserRootPat.MatchString(content) {
line := findLineNumber(content, dockerUserRootPat)
findings = append(findings, s.newFinding(
"Container runs as root user",
"Dockerfile explicitly sets USER root, which violates least privilege",
security.SeverityMedium,
security.CategoryMisconfiguration,
"CWE-250",
relPath, line,
))
} else if !dockerUserPat.MatchString(content) {
// No USER directive at all
findings = append(findings, s.newFinding(
"Container runs as root user",
"Dockerfile has no USER directive; container will run as root by default",
security.SeverityMedium,
security.CategoryMisconfiguration,
"CWE-250",
relPath, 1,
))
}
// Check for ADD with URL
if dockerAddURLPat.MatchString(content) {
line := findLineNumber(content, dockerAddURLPat)
findings = scanner.isKubernetesYAML function · go · L153-L160 (8 LOC)internal/security/scanner/config.go
func isKubernetesYAML(data []byte, relPath string) bool {
ext := filepath.Ext(relPath)
if ext != ".yaml" && ext != ".yml" {
return false
}
content := string(data)
return strings.Contains(content, "apiVersion:") || strings.Contains(content, "kind:")
}scanner.ConfigScanner.checkKubernetes method · go · L162-L215 (54 LOC)internal/security/scanner/config.go
func (s *ConfigScanner) checkKubernetes(data []byte, relPath string) []security.Finding {
var findings []security.Finding
content := string(data)
if k8sPrivilegedPat.MatchString(content) {
line := findLineNumber(content, k8sPrivilegedPat)
findings = append(findings, s.newFinding(
"Kubernetes container running in privileged mode",
"privileged: true grants the container nearly all host capabilities",
security.SeverityHigh,
security.CategoryMisconfiguration,
"CWE-250",
relPath, line,
))
}
if k8sHostNetworkPat.MatchString(content) {
line := findLineNumber(content, k8sHostNetworkPat)
findings = append(findings, s.newFinding(
"Kubernetes pod uses host network",
"hostNetwork: true exposes the pod to the host network stack",
security.SeverityMedium,
security.CategoryMisconfiguration,
"",
relPath, line,
))
}
if k8sHostPIDPat.MatchString(content) {
line := findLineNumber(content, k8sHostPIDPat)
findings = append(findings, s.newFindingscanner.isCIConfig function · go · L225-L237 (13 LOC)internal/security/scanner/config.go
func isCIConfig(relPath string) bool {
normalized := filepath.ToSlash(relPath)
if strings.HasPrefix(normalized, ".github/workflows/") && strings.HasSuffix(normalized, ".yml") {
return true
}
if normalized == ".gitlab-ci.yml" {
return true
}
if normalized == ".circleci/config.yml" {
return true
}
return false
}scanner.ConfigScanner.checkCIConfig method · go · L239-L265 (27 LOC)internal/security/scanner/config.go
func (s *ConfigScanner) checkCIConfig(data []byte, relPath string) []security.Finding {
var findings []security.Finding
scanner := bufio.NewScanner(bytes.NewReader(data))
lineNum := 0
for scanner.Scan() {
lineNum++
line := scanner.Text()
if ciSecretPat.MatchString(line) {
// Extract the value part to check if it's a variable reference.
value := extractConfigValue(line)
if value != "" && !ciSecretExcludePat.MatchString(value) {
findings = append(findings, s.newFinding(
"Potential secret in CI configuration",
fmt.Sprintf("Plain text secret/token/password found in CI config at line %d", lineNum),
security.SeverityHigh,
security.CategorySecretsExposure,
"CWE-798",
relPath, lineNum,
))
}
}
}
return findings
}scanner.extractConfigValue function · go · L268-L286 (19 LOC)internal/security/scanner/config.go
func extractConfigValue(line string) string {
line = strings.TrimSpace(line)
// Try key: value
if idx := strings.Index(line, ":"); idx >= 0 {
val := strings.TrimSpace(line[idx+1:])
val = strings.Trim(val, "\"'")
return val
}
// Try key=value
if idx := strings.Index(line, "="); idx >= 0 {
val := strings.TrimSpace(line[idx+1:])
val = strings.Trim(val, "\"'")
return val
}
return ""
}About: code-quality intelligence by Repobility · https://repobility.com
scanner.isConfigFile function · go · L295-L306 (12 LOC)internal/security/scanner/config.go
func isConfigFile(relPath string) bool {
ext := filepath.Ext(relPath)
switch ext {
case ".yaml", ".yml", ".toml", ".json", ".env", ".ini", ".conf", ".cfg", ".properties":
return true
}
baseName := filepath.Base(relPath)
if strings.HasPrefix(baseName, ".env") {
return true
}
return false
}scanner.ConfigScanner.checkGeneralConfig method · go · L308-L337 (30 LOC)internal/security/scanner/config.go
func (s *ConfigScanner) checkGeneralConfig(data []byte, relPath string) []security.Finding {
var findings []security.Finding
content := string(data)
if debugModePat.MatchString(content) {
line := findLineNumber(content, debugModePat)
findings = append(findings, s.newFinding(
"Debug mode enabled in configuration",
"Debug mode may expose sensitive information in production",
security.SeverityLow,
security.CategoryMisconfiguration,
"",
relPath, line,
))
}
if permissiveCORS.MatchString(content) {
line := findLineNumber(content, permissiveCORS)
findings = append(findings, s.newFinding(
"Permissive CORS configuration",
"Access-Control-Allow-Origin: * allows any domain to make requests",
security.SeverityMedium,
security.CategoryMisconfiguration,
"",
relPath, line,
))
}
return findings
}scanner.findLineNumber function · go · L342-L348 (7 LOC)internal/security/scanner/config.go
func findLineNumber(content string, pat *regexp.Regexp) int {
loc := pat.FindStringIndex(content)
if loc == nil {
return 1
}
return strings.Count(content[:loc[0]], "\n") + 1
}scanner.ConfigScanner.newFinding method · go · L350-L371 (22 LOC)internal/security/scanner/config.go
func (s *ConfigScanner) newFinding(title, description string, severity security.Severity, category security.Category, cwe, file string, line int) security.Finding {
s.mu.Lock()
s.findingCounter++
id := fmt.Sprintf("CFG-%04d", s.findingCounter)
s.mu.Unlock()
return security.Finding{
ID: id,
Scanner: "config",
Severity: severity,
Category: category,
Title: title,
Description: description,
Location: security.Location{
File: file,
StartLine: line,
EndLine: line,
},
CWE: cwe,
Confidence: security.ConfidenceHigh,
}
}scanner.NewCustomRuleScanner function · go · L28-L38 (11 LOC)internal/security/scanner/custom.go
func NewCustomRuleScanner(rules []security.CustomRule) *CustomRuleScanner {
var compiled []compiledCustomRule
for _, r := range rules {
re, err := regexp.Compile(r.Pattern)
if err != nil {
continue
}
compiled = append(compiled, compiledCustomRule{rule: r, re: re})
}
return &CustomRuleScanner{rules: compiled}
}scanner.CustomRuleScanner.Scan method · go · L44-L68 (25 LOC)internal/security/scanner/custom.go
func (s *CustomRuleScanner) Scan(ctx context.Context, target security.ScanTarget) ([]security.Finding, error) {
if len(s.rules) == 0 {
return nil, nil
}
files, err := security.CollectFiles(target, nil)
if err != nil {
return nil, fmt.Errorf("collecting files: %w", err)
}
var findings []security.Finding
for _, relPath := range files {
if ctx.Err() != nil {
return findings, ctx.Err()
}
absPath := filepath.Join(target.RootDir, relPath)
fileFindings, scanErr := s.scanFile(absPath, relPath)
if scanErr != nil {
continue
}
findings = append(findings, fileFindings...)
}
return findings, nil
}scanner.CustomRuleScanner.scanFile method · go · L70-L103 (34 LOC)internal/security/scanner/custom.go
func (s *CustomRuleScanner) scanFile(absPath, relPath string) ([]security.Finding, error) {
f, err := os.Open(absPath)
if err != nil {
return nil, err
}
defer f.Close()
var findings []security.Finding
scanner := bufio.NewScanner(f)
lineNum := 0
for scanner.Scan() {
lineNum++
line := scanner.Text()
for _, cr := range s.rules {
if cr.re.MatchString(line) {
findings = append(findings, security.Finding{
ID: cr.rule.ID,
Scanner: "custom-rules",
Severity: security.Severity(cr.rule.Severity),
Category: security.Category(cr.rule.Category),
Title: cr.rule.Title,
Location: security.Location{
File: relPath,
StartLine: lineNum,
EndLine: lineNum,
},
Evidence: line,
Confidence: security.ConfidenceHigh,
})
}
}
}
return findings, scanner.Err()
}scanner.NewDepScanner function · go · L45-L59 (15 LOC)internal/security/scanner/deps.go
func NewDepScanner(client *http.Client) *DepScanner {
s := &DepScanner{
client: client,
OSVBaseURL: defaultOSVBaseURL,
}
s.parsers = []lockfileParser{
{filename: "go.sum", ecosystem: "Go", parse: parseGoSum},
{filename: "package-lock.json", ecosystem: "npm", parse: parsePackageLock},
{filename: "requirements.txt", ecosystem: "PyPI", parse: parseRequirementsTxt},
{filename: "Gemfile.lock", ecosystem: "RubyGems", parse: parseGemfileLock},
{filename: "Cargo.lock", ecosystem: "crates.io", parse: parseCargoLock},
{filename: "Podfile.lock", ecosystem: "CocoaPods", parse: parsePodfileLock},
}
return s
}Repobility · code-quality intelligence · https://repobility.com
scanner.DepScanner.Scan method · go · L68-L115 (48 LOC)internal/security/scanner/deps.go
func (s *DepScanner) Scan(ctx context.Context, target security.ScanTarget) ([]security.Finding, error) {
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("dependency auditor cancelled: %w", err)
}
var findings []security.Finding
for _, parser := range s.parsers {
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("dependency auditor cancelled: %w", err)
}
lockfilePath := filepath.Join(target.RootDir, parser.filename)
data, err := os.ReadFile(lockfilePath)
if err != nil {
continue // lockfile not present — skip silently
}
deps, err := parser.parse(data)
if err != nil {
continue // parse error — skip silently
}
if s.client == nil {
continue // no HTTP client — skip OSV queries
}
for _, dep := range deps {
if err := ctx.Err(); err != nil {
return nil, fmt.Errorf("dependency auditor cancelled: %w", err)
}
vulnFindings, err := s.queryOSV(ctx, dep, parser.ecosystem, parser.filename)
if err != nil {
// OSV unavscanner.DepScanner.queryOSV method · go · L118-L160 (43 LOC)internal/security/scanner/deps.go
func (s *DepScanner) queryOSV(ctx context.Context, dep dependency, ecosystem, lockfile string) ([]security.Finding, error) {
reqBody := osvQueryRequest{
Package: osvPackage{
Name: dep.Name,
Ecosystem: ecosystem,
},
Version: dep.Version,
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return nil, fmt.Errorf("marshaling OSV request: %w", err)
}
url := s.OSVBaseURL + "/v1/query"
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(bodyBytes))
if err != nil {
return nil, fmt.Errorf("creating OSV request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := s.client.Do(req)
if err != nil {
return nil, fmt.Errorf("OSV API request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("OSV API returned status %d", resp.StatusCode)
}
var osvResp osvQueryResponse
if err := json.NewDecoder(resp.Body).Decode(&osvResp); err != nil {
returscanner.DepScanner.newVulnFinding method · go · L163-L195 (33 LOC)internal/security/scanner/deps.go
func (s *DepScanner) newVulnFinding(dep dependency, vuln osvVuln, sev security.Severity, lockfile string) security.Finding {
s.mu.Lock()
s.findingCounter++
id := fmt.Sprintf("DEP-%04d", s.findingCounter)
s.mu.Unlock()
var refs []string
for _, r := range vuln.References {
refs = append(refs, r.URL)
}
return security.Finding{
ID: id,
Scanner: "dependency-audit",
Severity: sev,
Category: security.CategoryVulnerableDep,
Title: fmt.Sprintf("Vulnerable dependency: %s@%s (%s)", dep.Name, dep.Version, vuln.ID),
Description: vuln.Summary,
Location: security.Location{
File: lockfile,
},
CWE: "CWE-1035",
Evidence: fmt.Sprintf("Package %s@%s has known vulnerability %s", dep.Name, dep.Version, vuln.ID),
Confidence: security.ConfidenceHigh,
References: refs,
Metadata: map[string]string{
"vuln_id": vuln.ID,
"package": dep.Name,
"version": dep.Version,
"ecosystem": lockfile,
},
}
}scanner.DepScanner.newInfoFinding method · go · L198-L217 (20 LOC)internal/security/scanner/deps.go
func (s *DepScanner) newInfoFinding(title, description, lockfile string) security.Finding {
s.mu.Lock()
s.findingCounter++
id := fmt.Sprintf("DEP-%04d", s.findingCounter)
s.mu.Unlock()
return security.Finding{
ID: id,
Scanner: "dependency-audit",
Severity: security.SeverityInfo,
Category: security.CategoryVulnerableDep,
Title: title,
Description: description,
Location: security.Location{
File: lockfile,
},
CWE: "CWE-1035",
Confidence: security.ConfidenceLow,
}
}scanner.classifyOSVSeverity function · go · L220-L238 (19 LOC)internal/security/scanner/deps.go
func classifyOSVSeverity(vuln osvVuln) security.Severity {
for _, sev := range vuln.Severity {
if sev.Type == "CVSS_V3" {
score := parseCVSSScore(sev.Score)
switch {
case score >= 9.0:
return security.SeverityCritical
case score >= 7.0:
return security.SeverityHigh
case score >= 4.0:
return security.SeverityMedium
default:
return security.SeverityLow
}
}
}
// No CVSS score available — default to Medium.
return security.SeverityMedium
}scanner.parseGoSum function · go · L306-L342 (37 LOC)internal/security/scanner/deps.go
func parseGoSum(data []byte) ([]dependency, error) {
seen := make(map[string]bool)
var deps []dependency
scanner := bufio.NewScanner(bytes.NewReader(data))
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" {
continue
}
parts := strings.Fields(line)
if len(parts) < 2 {
continue
}
name := parts[0]
version := parts[1]
// Skip /go.mod hash lines.
if strings.HasSuffix(version, "/go.mod") {
continue
}
// Remove the h1: hash suffix from version if present.
// go.sum format: module version h1:hash
// version may have a /go.mod suffix (already handled above).
key := name + "@" + version
if seen[key] {
continue
}
seen[key] = true
deps = append(deps, dependency{Name: name, Version: strings.TrimPrefix(version, "v")})
}
return deps, scanner.Err()
}scanner.parsePackageLock function · go · L346-L385 (40 LOC)internal/security/scanner/deps.go
func parsePackageLock(data []byte) ([]dependency, error) {
var lockfile struct {
Packages map[string]packageLockEntry `json:"packages"`
Dependencies map[string]packageLockEntry `json:"dependencies"`
}
if err := json.Unmarshal(data, &lockfile); err != nil {
return nil, fmt.Errorf("parsing package-lock.json: %w", err)
}
var deps []dependency
// lockfileVersion 2/3: uses "packages" with "node_modules/" prefixes.
for key, entry := range lockfile.Packages {
if entry.Version == "" {
continue
}
// Extract package name from "node_modules/name" path.
name := key
if idx := strings.LastIndex(key, "node_modules/"); idx >= 0 {
name = key[idx+len("node_modules/"):]
}
if name == "" {
continue
}
deps = append(deps, dependency{Name: name, Version: entry.Version})
}
// lockfileVersion 1: uses "dependencies" with flat names.
if len(deps) == 0 {
for name, entry := range lockfile.Dependencies {
if entry.Version == "" {
continue
}
deps = appescanner.parseRequirementsTxt function · go · L393-L410 (18 LOC)internal/security/scanner/deps.go
func parseRequirementsTxt(data []byte) ([]dependency, error) {
var deps []dependency
re := regexp.MustCompile(`^([a-zA-Z0-9._-]+)==([^\s#]+)`)
scanner := bufio.NewScanner(bytes.NewReader(data))
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
matches := re.FindStringSubmatch(line)
if matches != nil {
deps = append(deps, dependency{Name: matches[1], Version: matches[2]})
}
}
return deps, scanner.Err()
}Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
scanner.parseGemfileLock function · go · L413-L441 (29 LOC)internal/security/scanner/deps.go
func parseGemfileLock(data []byte) ([]dependency, error) {
var deps []dependency
re := regexp.MustCompile(`^\s{4}(\S+)\s+\(([^)]+)\)`)
inSpecs := false
scanner := bufio.NewScanner(bytes.NewReader(data))
for scanner.Scan() {
line := scanner.Text()
if strings.TrimSpace(line) == "specs:" {
inSpecs = true
continue
}
// End of specs section when we hit a non-indented line (except blank).
if inSpecs && len(line) > 0 && line[0] != ' ' {
inSpecs = false
continue
}
if inSpecs {
matches := re.FindStringSubmatch(line)
if matches != nil {
deps = append(deps, dependency{Name: matches[1], Version: matches[2]})
}
}
}
return deps, scanner.Err()
}scanner.parseCargoLock function · go · L444-L474 (31 LOC)internal/security/scanner/deps.go
func parseCargoLock(data []byte) ([]dependency, error) {
var deps []dependency
var currentName, currentVersion string
scanner := bufio.NewScanner(bytes.NewReader(data))
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "[[package]]" {
if currentName != "" && currentVersion != "" {
deps = append(deps, dependency{Name: currentName, Version: currentVersion})
}
currentName = ""
currentVersion = ""
continue
}
if strings.HasPrefix(line, "name = ") {
currentName = unquoteTOML(strings.TrimPrefix(line, "name = "))
} else if strings.HasPrefix(line, "version = ") {
currentVersion = unquoteTOML(strings.TrimPrefix(line, "version = "))
}
}
// Don't forget the last package block.
if currentName != "" && currentVersion != "" {
deps = append(deps, dependency{Name: currentName, Version: currentVersion})
}
return deps, scanner.Err()
}scanner.parsePodfileLock function · go · L477-L504 (28 LOC)internal/security/scanner/deps.go
func parsePodfileLock(data []byte) ([]dependency, error) {
var deps []dependency
re := regexp.MustCompile(`^\s+-\s+(\S+)\s+\(([^)]+)\)`)
inPods := false
scanner := bufio.NewScanner(bytes.NewReader(data))
for scanner.Scan() {
line := scanner.Text()
if strings.TrimSpace(line) == "PODS:" {
inPods = true
continue
}
// End of PODS section at next top-level key.
if inPods && len(line) > 0 && line[0] != ' ' {
break
}
if inPods {
matches := re.FindStringSubmatch(line)
if matches != nil {
deps = append(deps, dependency{Name: matches[1], Version: matches[2]})
}
}
}
return deps, scanner.Err()
}