Skip to content

Commit 7240b91

Browse files
works with semgrep all definitions file
wip: semgrep patterns empty
1 parent 396a734 commit 7240b91

File tree

8 files changed

+116333
-15
lines changed

8 files changed

+116333
-15
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ go.work.sum
2727
# Codacy CLI
2828
cli-v2
2929
codacy-cli
30+
31+
#Macos
32+
.DS_Store

cmd/init.go

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

2020
"github.com/spf13/cobra"
21+
"gopkg.in/yaml.v3"
2122
)
2223

2324
const CodacyApiBase = "https://app.codacy.com"
@@ -141,10 +142,11 @@ func configFileTemplate(tools []tools.Tool) string {
141142

142143
// Default versions
143144
defaultVersions := map[string]string{
144-
ESLint: "9.3.0",
145-
Trivy: "0.59.1",
146-
PyLint: "3.3.6",
147-
PMD: "6.55.0",
145+
ESLint: "9.3.0",
146+
Trivy: "0.59.1",
147+
PyLint: "3.3.6",
148+
PMD: "6.55.0",
149+
Semgrep: "1.78.0",
148150
}
149151

150152
// Build map of enabled tools with their versions
@@ -188,10 +190,11 @@ func configFileTemplate(tools []tools.Tool) string {
188190
if len(tools) > 0 {
189191
// Add only the tools that are in the API response (enabled tools)
190192
uuidToName := map[string]string{
191-
ESLint: "eslint",
192-
Trivy: "trivy",
193-
PyLint: "pylint",
194-
PMD: "pmd",
193+
ESLint: "eslint",
194+
Trivy: "trivy",
195+
PyLint: "pylint",
196+
PMD: "pmd",
197+
Semgrep: "semgrep",
195198
}
196199

197200
for uuid, name := range uuidToName {
@@ -205,6 +208,7 @@ func configFileTemplate(tools []tools.Tool) string {
205208
sb.WriteString(fmt.Sprintf(" - trivy@%s\n", defaultVersions[Trivy]))
206209
sb.WriteString(fmt.Sprintf(" - pylint@%s\n", defaultVersions[PyLint]))
207210
sb.WriteString(fmt.Sprintf(" - pmd@%s\n", defaultVersions[PMD]))
211+
sb.WriteString(fmt.Sprintf(" - semgrep@%s\n", defaultVersions[Semgrep]))
208212
}
209213

210214
return sb.String()
@@ -257,7 +261,8 @@ func buildRepositoryConfigurationFiles(token string) error {
257261

258262
// Only generate config files for tools not using their own config file
259263
for _, tool := range configuredToolsWithUI {
260-
url := fmt.Sprintf("%s/api/v3/analysis/organizations/%s/%s/repositories/%s/tools/%s/patterns?enabled=true",
264+
265+
url := fmt.Sprintf("%s/api/v3/analysis/organizations/%s/%s/repositories/%s/tools/%s/patterns?enabled=true&limit=1000",
261266
CodacyApiBase,
262267
initFlags.provider,
263268
initFlags.organization,
@@ -380,6 +385,19 @@ func createToolFileConfigurations(tool tools.Tool, patternConfiguration []domain
380385
}
381386
}
382387
fmt.Println("Pylint configuration created based on Codacy settings")
388+
case Semgrep:
389+
if len(patternConfiguration) > 0 {
390+
err := createSemgrepConfigFile(patternConfiguration, toolsConfigDir)
391+
if err != nil {
392+
return fmt.Errorf("failed to create Semgrep config: %v", err)
393+
}
394+
} else {
395+
err := createDefaultSemgrepConfigFile(toolsConfigDir)
396+
if err != nil {
397+
return fmt.Errorf("failed to create default Semgrep config: %v", err)
398+
}
399+
}
400+
fmt.Println("Semgrep configuration created based on Codacy settings")
383401
}
384402
return nil
385403
}
@@ -434,6 +452,128 @@ func createDefaultEslintConfigFile(toolsConfigDir string) error {
434452
return os.WriteFile(filepath.Join(toolsConfigDir, "eslint.config.mjs"), []byte(content), utils.DefaultFilePerms)
435453
}
436454

455+
// SemgrepRulesFile represents the structure of the rules.yaml file
456+
type SemgrepRulesFile struct {
457+
Rules []map[string]interface{} `yaml:"rules"`
458+
}
459+
460+
// createSemgrepConfigFile creates a semgrep.yaml configuration file based on the API configuration
461+
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)
547+
}
548+
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)
553+
}
554+
555+
// createDefaultSemgrepConfigFile creates a default semgrep.yaml configuration file
556+
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)
569+
}
570+
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)
575+
}
576+
437577
// cleanConfigDirectory removes all previous configuration files in the tools-configs directory
438578
func cleanConfigDirectory(toolsConfigDir string) error {
439579
// Check if directory exists
@@ -462,8 +602,9 @@ func cleanConfigDirectory(toolsConfigDir string) error {
462602
}
463603

464604
const (
465-
ESLint string = "f8b29663-2cb2-498d-b923-a10c6a8c05cd"
466-
Trivy string = "2fd7fbe0-33f9-4ab3-ab73-e9b62404e2cb"
467-
PMD string = "9ed24812-b6ee-4a58-9004-0ed183c45b8f"
468-
PyLint string = "31677b6d-4ae0-4f56-8041-606a8d7a8e61"
605+
ESLint string = "f8b29663-2cb2-498d-b923-a10c6a8c05cd"
606+
Trivy string = "2fd7fbe0-33f9-4ab3-ab73-e9b62404e2cb"
607+
PMD string = "9ed24812-b6ee-4a58-9004-0ed183c45b8f"
608+
PyLint string = "31677b6d-4ae0-4f56-8041-606a8d7a8e61"
609+
Semgrep string = "6792c561-236d-41b7-ba5e-9d6bee0d548b"
469610
)

domain/patternConfiguration.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,22 @@ type ParameterConfiguration struct {
66
}
77

88
type PatternDefinition struct {
9-
Id string `json:"id"`
9+
Id string `json:"id"`
10+
Category string `json:"category"`
11+
Level string `json:"level"`
12+
SeverityLevel string `json:"severityLevel"`
13+
Enabled bool `json:"enabled"`
14+
Parameters []ParameterConfiguration `json:"parameters"`
15+
Title string `json:"title"`
16+
Description string `json:"description"`
17+
Explanation string `json:"explanation"`
18+
Languages []string `json:"languages"`
19+
TimeToFix int `json:"timeToFix"`
1020
}
1121

1222
type PatternConfiguration struct {
1323
PatternDefinition PatternDefinition `json:"patternDefinition"`
1424
Parameters []ParameterConfiguration
25+
Enabled bool `json:"enabled"`
26+
IsCustom bool `json:"isCustom"`
1527
}

0 commit comments

Comments
 (0)