Skip to content

Commit 068c632

Browse files
general code clean
1 parent 8a348dc commit 068c632

File tree

5 files changed

+296
-318
lines changed

5 files changed

+296
-318
lines changed

.codacy/codacy.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
runtimes:
22
- node@22.2.0
3-
- python@3.11.11
43
tools:
5-
- eslint@9.3.0
64
- trivy@0.59.1
7-
- pylint@3.3.6
85
- pmd@6.55.0
9-
- semgrep@1.78.0
6+
- semgrep@1.78.0
7+
- eslint@8.57.0

cmd/init.go

Lines changed: 36 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"time"
1919

2020
"github.com/spf13/cobra"
21-
"gopkg.in/yaml.v3"
2221
)
2322

2423
const CodacyApiBase = "https://app.codacy.com"
@@ -459,119 +458,50 @@ type SemgrepRulesFile struct {
459458

460459
// createSemgrepConfigFile creates a semgrep.yaml configuration file based on the API configuration
461460
func createSemgrepConfigFile(config []domain.PatternConfiguration, toolsConfigDir string) error {
462-
// When specific patterns are configured, filter rules from rules.yaml
463-
if len(config) > 0 {
464-
// First try to read the rules.yaml file
465-
rulesFile := filepath.Join("plugins", "tools", "semgrep", "rules.yaml")
466-
if _, err := os.Stat(rulesFile); err == nil {
467-
// Read and parse the rules.yaml file
468-
data, err := os.ReadFile(rulesFile)
469-
if err != nil {
470-
fmt.Printf("Warning: Failed to read rules.yaml: %v\n", err)
471-
// Fall back to the old method
472-
semgrepConfigurationString := tools.CreateSemgrepConfig(config)
473-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), []byte(semgrepConfigurationString), utils.DefaultFilePerms)
474-
}
475-
476-
// Parse the YAML file just enough to get the rules array
477-
var allRules SemgrepRulesFile
478-
if err := yaml.Unmarshal(data, &allRules); err != nil {
479-
fmt.Printf("Warning: Failed to parse rules.yaml: %v\n", err)
480-
// Fall back to the old method
481-
semgrepConfigurationString := tools.CreateSemgrepConfig(config)
482-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), []byte(semgrepConfigurationString), utils.DefaultFilePerms)
483-
}
484-
485-
// Create a map of enabled pattern IDs for faster lookup
486-
enabledPatterns := make(map[string]bool)
487-
for _, pattern := range config {
488-
if pattern.Enabled && pattern.PatternDefinition.Enabled {
489-
// Extract rule ID from pattern ID
490-
parts := strings.SplitN(pattern.PatternDefinition.Id, "_", 2)
491-
if len(parts) == 2 {
492-
ruleID := parts[1]
493-
enabledPatterns[ruleID] = true
494-
}
495-
}
496-
}
497-
498-
// Filter the rules based on enabled patterns
499-
var filteredRules SemgrepRulesFile
500-
filteredRules.Rules = []map[string]interface{}{}
501-
502-
for _, rule := range allRules.Rules {
503-
// Get the rule ID
504-
if ruleID, ok := rule["id"].(string); ok && enabledPatterns[ruleID] {
505-
// If this rule is enabled, include it
506-
filteredRules.Rules = append(filteredRules.Rules, rule)
507-
}
508-
}
509-
510-
// If no rules match, use the old method
511-
if len(filteredRules.Rules) == 0 {
512-
fmt.Println("Warning: No matching rules found in rules.yaml")
513-
semgrepConfigurationString := tools.CreateSemgrepConfig(config)
514-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), []byte(semgrepConfigurationString), utils.DefaultFilePerms)
515-
}
516-
517-
// Marshal the filtered rules back to YAML
518-
filteredData, err := yaml.Marshal(filteredRules)
519-
if err != nil {
520-
fmt.Printf("Warning: Failed to marshal filtered rules: %v\n", err)
521-
// Fall back to the old method
522-
semgrepConfigurationString := tools.CreateSemgrepConfig(config)
523-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), []byte(semgrepConfigurationString), utils.DefaultFilePerms)
524-
}
525-
526-
// Write the filtered rules to semgrep.yaml
527-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), filteredData, utils.DefaultFilePerms)
528-
}
529-
530-
// If rules.yaml doesn't exist, fall back to the old method
531-
semgrepConfigurationString := tools.CreateSemgrepConfig(config)
532-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), []byte(semgrepConfigurationString), utils.DefaultFilePerms)
533-
}
534-
535-
// For default case with no specific patterns, use the entire rules.yaml
536-
rulesFile := filepath.Join("plugins", "tools", "semgrep", "rules.yaml")
537-
if _, err := os.Stat(rulesFile); err == nil {
538-
data, err := os.ReadFile(rulesFile)
539-
if err != nil {
540-
fmt.Printf("Warning: Failed to read rules.yaml: %v\n", err)
541-
// Fall back to the old method for default config
542-
emptyConfig := []domain.PatternConfiguration{}
543-
content := tools.CreateSemgrepConfig(emptyConfig)
544-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), []byte(content), utils.DefaultFilePerms)
545-
}
546-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), data, utils.DefaultFilePerms)
461+
// Use the refactored function from tools package
462+
configData, err := tools.GetSemgrepConfig(config)
463+
if err != nil {
464+
// Log the error but continue with a minimal configuration
465+
fmt.Printf("Warning: %v. Creating a minimal configuration.\n", err)
466+
467+
// Create a minimal configuration
468+
minimalConfig := []byte(`rules:
469+
- id: all
470+
pattern: |
471+
$X
472+
message: "Semgrep analysis"
473+
languages: [generic]
474+
severity: INFO
475+
`)
476+
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), minimalConfig, utils.DefaultFilePerms)
547477
}
548478

549-
// Fall back to default config
550-
emptyConfig := []domain.PatternConfiguration{}
551-
content := tools.CreateSemgrepConfig(emptyConfig)
552-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), []byte(content), utils.DefaultFilePerms)
479+
// Write to file
480+
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), configData, utils.DefaultFilePerms)
553481
}
554482

555483
// createDefaultSemgrepConfigFile creates a default semgrep.yaml configuration file
556484
func createDefaultSemgrepConfigFile(toolsConfigDir string) error {
557-
// Use rules.yaml as the default
558-
rulesFile := filepath.Join("plugins", "tools", "semgrep", "rules.yaml")
559-
if _, err := os.Stat(rulesFile); err == nil {
560-
data, err := os.ReadFile(rulesFile)
561-
if err != nil {
562-
fmt.Printf("Warning: Failed to read rules.yaml: %v\n", err)
563-
// Fall back to the old method
564-
emptyConfig := []domain.PatternConfiguration{}
565-
content := tools.CreateSemgrepConfig(emptyConfig)
566-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), []byte(content), utils.DefaultFilePerms)
567-
}
568-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), data, utils.DefaultFilePerms)
485+
// Use the refactored function from tools package
486+
configData, err := tools.GetDefaultSemgrepConfig()
487+
if err != nil {
488+
// Log the error but continue with a minimal configuration
489+
fmt.Printf("Warning: %v. Creating a minimal configuration.\n", err)
490+
491+
// Create a minimal configuration
492+
minimalConfig := []byte(`rules:
493+
- id: all
494+
pattern: |
495+
$X
496+
message: "Semgrep analysis"
497+
languages: [generic]
498+
severity: INFO
499+
`)
500+
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), minimalConfig, utils.DefaultFilePerms)
569501
}
570502

571-
// Fall back to the old method if rules.yaml doesn't exist
572-
emptyConfig := []domain.PatternConfiguration{}
573-
content := tools.CreateSemgrepConfig(emptyConfig)
574-
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), []byte(content), utils.DefaultFilePerms)
503+
// Write to file
504+
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), configData, utils.DefaultFilePerms)
575505
}
576506

577507
// cleanConfigDirectory removes all previous configuration files in the tools-configs directory

plugins/tools/semgrep/rules.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100813,7 +100813,7 @@ rules:
100813100813
- "A01:2021-Broken Access Control"
100814100814
cwe: "CWE-22"
100815100815
shortDescription: "Improper limitation of a pathname to a restricted directory
100816-
('Path Traversal')"
100816+
('Path Traversal')"
100817100817
references:
100818100818
- "https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/07-Input_Validation_Testing/11.1-Testing_for_Local_File_Inclusion"
100819100819
- "https://github.com/semgrep/semgrep-rules/blob/develop/ruby/rails/security/brakeman/check-render-local-file-include.yaml"

tools/semgrepConfigCreator.go

Lines changed: 67 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -3,127 +3,91 @@ package tools
33
import (
44
"codacy/cli-v2/domain"
55
"fmt"
6+
"os"
7+
"path/filepath"
68
"strings"
9+
10+
"gopkg.in/yaml.v3"
711
)
812

9-
// supportedLanguages is a list of all languages supported by Semgrep
10-
var supportedLanguages = []string{
11-
"apex", "bash", "c", "c#", "c++", "cairo",
12-
"clojure", "cpp", "csharp", "dart", "docker",
13-
"dockerfile", "elixir", "ex", "generic", "go",
14-
"golang", "hack", "hcl", "html", "java",
15-
"javascript", "js", "json", "jsonnet", "julia",
16-
"kotlin", "kt", "lisp", "lua", "move_on_aptos",
17-
"none", "ocaml", "php", "promql", "proto",
18-
"proto3", "protobuf", "py", "python", "python2",
19-
"python3", "ql", "r", "regex", "ruby",
20-
"rust", "scala", "scheme", "sh", "sol",
21-
"solidity", "swift", "terraform", "tf", "ts",
22-
"typescript", "vue", "xml", "yaml",
13+
// semgrepRulesFile represents the structure of the rules.yaml file
14+
type semgrepRulesFile struct {
15+
Rules []map[string]interface{} `yaml:"rules"`
2316
}
2417

25-
// CreateSemgrepConfig generates a Semgrep configuration based on the tool configuration
26-
func CreateSemgrepConfig(config []domain.PatternConfiguration) string {
27-
// Build the rules list
28-
var rules []string
29-
30-
// Process each pattern from the API
31-
for _, pattern := range config {
18+
// FilterRulesFromFile extracts enabled rules from a rules.yaml file based on configuration
19+
func FilterRulesFromFile(rulesFilePath string, config []domain.PatternConfiguration) ([]byte, error) {
20+
// Read the rules.yaml file
21+
data, err := os.ReadFile(rulesFilePath)
22+
if err != nil {
23+
return nil, fmt.Errorf("failed to read rules file: %w", err)
24+
}
3225

33-
// Skip if pattern is not enabled
34-
if !pattern.Enabled || !pattern.PatternDefinition.Enabled {
35-
continue
36-
}
26+
// Parse the YAML file
27+
var allRules semgrepRulesFile
28+
if err := yaml.Unmarshal(data, &allRules); err != nil {
29+
return nil, fmt.Errorf("failed to parse rules file: %w", err)
30+
}
3731

38-
// Skip if no languages defined
39-
if len(pattern.PatternDefinition.Languages) == 0 {
40-
continue
32+
// Create a map of enabled pattern IDs for faster lookup
33+
enabledPatterns := make(map[string]bool)
34+
for _, pattern := range config {
35+
if pattern.Enabled && pattern.PatternDefinition.Enabled {
36+
// Extract rule ID from pattern ID
37+
parts := strings.SplitN(pattern.PatternDefinition.Id, "_", 2)
38+
if len(parts) == 2 {
39+
ruleID := parts[1]
40+
enabledPatterns[ruleID] = true
41+
}
4142
}
43+
}
4244

43-
// Get the first language (Semgrep only supports one language per rule)
44-
language := strings.ToLower(pattern.PatternDefinition.Languages[0])
45-
46-
// Map language names to Semgrep supported languages
47-
switch language {
48-
case "csharp":
49-
language = "c#"
50-
case "cpp":
51-
language = "c++"
52-
case "golang":
53-
language = "go"
54-
case "js":
55-
language = "javascript"
56-
case "kt":
57-
language = "kotlin"
58-
case "py":
59-
language = "python"
60-
case "sh":
61-
language = "bash"
62-
case "tf":
63-
language = "terraform"
64-
case "ts":
65-
language = "typescript"
66-
}
45+
// Filter the rules based on enabled patterns
46+
var filteredRules semgrepRulesFile
47+
filteredRules.Rules = []map[string]interface{}{}
6748

68-
// Skip if language is not supported by Semgrep
69-
isSupported := false
70-
for _, supportedLang := range supportedLanguages {
71-
if language == supportedLang {
72-
isSupported = true
73-
break
74-
}
75-
}
76-
if !isSupported {
77-
continue
49+
for _, rule := range allRules.Rules {
50+
// Get the rule ID
51+
if ruleID, ok := rule["id"].(string); ok && enabledPatterns[ruleID] {
52+
// If this rule is enabled, include it
53+
filteredRules.Rules = append(filteredRules.Rules, rule)
7854
}
55+
}
7956

80-
// Extract rule ID from pattern ID
81-
parts := strings.SplitN(pattern.PatternDefinition.Id, "_", 2)
82-
if len(parts) != 2 {
83-
continue // Skip invalid pattern IDs
84-
}
57+
// If no rules match, return an error
58+
if len(filteredRules.Rules) == 0 {
59+
return nil, fmt.Errorf("no matching rules found")
60+
}
8561

86-
// The rest is the rule path
87-
rulePath := parts[1]
62+
// Marshal the filtered rules back to YAML
63+
return yaml.Marshal(filteredRules)
64+
}
8865

89-
// Ensure we have a valid ID
90-
if rulePath == "" {
91-
rulePath = "default_rule"
92-
}
66+
// GetSemgrepConfig gets the Semgrep configuration based on the pattern configuration
67+
func GetSemgrepConfig(config []domain.PatternConfiguration) ([]byte, error) {
68+
// Get the default rules file location
69+
rulesFile := filepath.Join("plugins", "tools", "semgrep", "rules.yaml")
9370

94-
// Create rule entry
95-
rule := fmt.Sprintf(` - id: %s
96-
pattern: |
97-
$X
98-
message: "Semgrep rule: %s"
99-
languages: [%s]
100-
severity: %s`,
101-
strings.ReplaceAll(rulePath, ".", "_"), // Replace dots with underscores in ID
102-
rulePath,
103-
language,
104-
strings.ToUpper(pattern.PatternDefinition.SeverityLevel))
105-
106-
rules = append(rules, rule)
71+
// Check if it exists and config is not empty
72+
if _, err := os.Stat(rulesFile); err == nil && len(config) > 0 {
73+
// Try to filter rules from the file
74+
return FilterRulesFromFile(rulesFile, config)
10775
}
10876

109-
// If no rules were added, use a default configuration
110-
if len(rules) == 0 {
111-
return `rules:
112-
- id: default_rule
113-
pattern: |
114-
$X
115-
message: "Semgrep analysis"
116-
languages: [generic]
117-
severity: INFO
118-
`
119-
}
77+
// If rules.yaml doesn't exist or config is empty, return an error
78+
return nil, fmt.Errorf("rules.yaml not found or empty configuration")
79+
}
80+
81+
// GetDefaultSemgrepConfig gets the default Semgrep configuration
82+
func GetDefaultSemgrepConfig() ([]byte, error) {
83+
// Get the default rules file location
84+
rulesFile := filepath.Join("plugins", "tools", "semgrep", "rules.yaml")
12085

121-
// Generate semgrep.yaml content
122-
var contentBuilder strings.Builder
123-
contentBuilder.WriteString("rules:\n")
124-
for _, rule := range rules {
125-
contentBuilder.WriteString(rule + "\n")
86+
// If the file exists, return its contents
87+
if _, err := os.Stat(rulesFile); err == nil {
88+
return os.ReadFile(rulesFile)
12689
}
12790

128-
return contentBuilder.String()
91+
// Return an error if rules.yaml doesn't exist
92+
return nil, fmt.Errorf("rules.yaml not found")
12993
}

0 commit comments

Comments
 (0)