Skip to content

Commit e14fa31

Browse files
Merge branch 'main' into PLUTO-1399-run-tools-for-supported-languages
2 parents 7039d67 + 333782d commit e14fa31

22 files changed

+114579
-31
lines changed

.codacy/codacy.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ tools:
88
99
1010
11+

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,4 @@ codacy-cli
3333
.cursor/rules/codacy.mdc
3434

3535
#Macos
36-
.DS_Store
36+
.DS_Store

cmd/analyze.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,15 @@ func runDartAnalyzer(workDirectory string, pathsToCheck []string, outputFile str
352352
return tools.RunDartAnalyzer(workDirectory, dartanalyzer.InstallDir, dartanalyzer.Binaries["dart"], pathsToCheck, outputFile, outputFormat)
353353
}
354354

355+
func runSemgrepAnalysis(workDirectory string, pathsToCheck []string, outputFile string, outputFormat string) error {
356+
semgrep := config.Config.Tools()["semgrep"]
357+
if semgrep == nil {
358+
log.Fatal("Semgrep tool configuration not found")
359+
}
360+
361+
return tools.RunSemgrep(workDirectory, semgrep, pathsToCheck, outputFile, outputFormat)
362+
}
363+
355364
var analyzeCmd = &cobra.Command{
356365
Use: "analyze",
357366
Short: "Runs all configured linters.",
@@ -450,6 +459,8 @@ func runTool(workDirectory string, toolName string, args []string, outputFile st
450459
return runPmdAnalysis(workDirectory, args, outputFile, outputFormat)
451460
case "pylint":
452461
return runPylintAnalysis(workDirectory, args, outputFile, outputFormat)
462+
case "semgrep":
463+
return runSemgrepAnalysis(workDirectory, args, outputFile, outputFormat)
453464
case "dartanalyzer":
454465
return runDartAnalyzer(workDirectory, args, outputFile, outputFormat)
455466
default:

cmd/init.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ func configFileTemplate(tools []tools.Tool) string {
146146
PyLint: "3.3.6",
147147
PMD: "6.55.0",
148148
DartAnalyzer: "3.7.2",
149+
Semgrep: "1.78.0",
149150
}
150151

151152
// Build map of enabled tools with their versions
@@ -200,6 +201,7 @@ func configFileTemplate(tools []tools.Tool) string {
200201
PyLint: "pylint",
201202
PMD: "pmd",
202203
DartAnalyzer: "dartanalyzer",
204+
Semgrep: "semgrep",
203205
}
204206

205207
for uuid, name := range uuidToName {
@@ -214,6 +216,7 @@ func configFileTemplate(tools []tools.Tool) string {
214216
sb.WriteString(fmt.Sprintf(" - pylint@%s\n", defaultVersions[PyLint]))
215217
sb.WriteString(fmt.Sprintf(" - pmd@%s\n", defaultVersions[PMD]))
216218
sb.WriteString(fmt.Sprintf(" - dartanalyzer@%s\n", defaultVersions[DartAnalyzer]))
219+
sb.WriteString(fmt.Sprintf(" - semgrep@%s\n", defaultVersions[Semgrep]))
217220
}
218221

219222
return sb.String()
@@ -280,7 +283,8 @@ func buildRepositoryConfigurationFiles(token string) error {
280283

281284
// Only generate config files for tools not using their own config file
282285
for _, tool := range configuredToolsWithUI {
283-
url := fmt.Sprintf("%s/api/v3/analysis/organizations/%s/%s/repositories/%s/tools/%s/patterns?enabled=true",
286+
287+
url := fmt.Sprintf("%s/api/v3/analysis/organizations/%s/%s/repositories/%s/tools/%s/patterns?enabled=true&limit=1000",
284288
CodacyApiBase,
285289
initFlags.provider,
286290
initFlags.organization,
@@ -356,7 +360,7 @@ func createToolFileConfigurations(tool tools.Tool, patternConfiguration []domain
356360
if err != nil {
357361
return fmt.Errorf("failed to write eslint config: %v", err)
358362
}
359-
fmt.Println("ESLint configuration created based on Codacy settings")
363+
fmt.Println("ESLint configuration created based on Codacy settings. Ignoring plugin rules. ESLint plugins are not supported yet.")
360364
} else {
361365
err := createDefaultEslintConfigFile(toolsConfigDir)
362366
if err != nil {
@@ -410,6 +414,13 @@ func createToolFileConfigurations(tool tools.Tool, patternConfiguration []domain
410414
return fmt.Errorf("failed to create Dart Analyzer config: %v", err)
411415
}
412416
}
417+
case Semgrep:
418+
if len(patternConfiguration) > 0 {
419+
err := createSemgrepConfigFile(patternConfiguration, toolsConfigDir)
420+
if err != nil {
421+
return fmt.Errorf("failed to create Semgrep config: %v", err)
422+
}
423+
}
413424
}
414425
return nil
415426
}
@@ -470,6 +481,24 @@ func createDefaultEslintConfigFile(toolsConfigDir string) error {
470481
return os.WriteFile(filepath.Join(toolsConfigDir, "eslint.config.mjs"), []byte(content), utils.DefaultFilePerms)
471482
}
472483

484+
// SemgrepRulesFile represents the structure of the rules.yaml file
485+
type SemgrepRulesFile struct {
486+
Rules []map[string]interface{} `yaml:"rules"`
487+
}
488+
489+
// createSemgrepConfigFile creates a semgrep.yaml configuration file based on the API configuration
490+
func createSemgrepConfigFile(config []domain.PatternConfiguration, toolsConfigDir string) error {
491+
// Use the refactored function from tools package
492+
configData, err := tools.GetSemgrepConfig(config)
493+
494+
if err != nil {
495+
return fmt.Errorf("failed to create Semgrep config: %v", err)
496+
}
497+
498+
// Write to file
499+
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), configData, utils.DefaultFilePerms)
500+
}
501+
473502
// cleanConfigDirectory removes all previous configuration files in the tools-configs directory
474503
func cleanConfigDirectory(toolsConfigDir string) error {
475504
// Check if directory exists
@@ -503,4 +532,5 @@ const (
503532
PMD string = "9ed24812-b6ee-4a58-9004-0ed183c45b8f"
504533
PyLint string = "31677b6d-4ae0-4f56-8041-606a8d7a8e61"
505534
DartAnalyzer string = "d203d615-6cf1-41f9-be5f-e2f660f7850f"
535+
Semgrep string = "6792c561-236d-41b7-ba5e-9d6bee0d548b"
506536
)

cmd/upload.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func processSarif(sarif Sarif) [][]map[string]interface{} {
9797
codacyIssues = append(codacyIssues, map[string]interface{}{
9898
"source": location.PhysicalLocation.ArtifactLocation.URI,
9999
"line": location.PhysicalLocation.Region.StartLine,
100-
"type": modifiedType,
100+
"type": pattern.ID,
101101
"message": result.Message.Text,
102102
"level": pattern.Level,
103103
"category": pattern.Category,
@@ -208,7 +208,7 @@ func resultsFinalWithAPIToken(commitUUID string, apiToken string, provider strin
208208

209209
func getPatternByID(patterns []Pattern, patternID string) *Pattern {
210210
for _, p := range patterns {
211-
if p.ID == patternID {
211+
if strings.EqualFold(p.ID, patternID) {
212212
return &p
213213
}
214214
}

config/config.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,15 @@ func NewConfigType(repositoryDirectory string, repositoryCache string, globalCac
110110
c.toolsDirectory = filepath.Join(c.globalCacheDirectory, "tools")
111111
c.toolsConfigDirectory = filepath.Join(c.localCodacyDirectory, "tools-configs")
112112

113-
c.projectConfigFile = filepath.Join(c.localCodacyDirectory, "codacy.yaml")
113+
// If codacy.yml exists, we should rely on it
114+
ymlPath := filepath.Join(c.localCodacyDirectory, "codacy.yml")
115+
if _, err := os.Stat(ymlPath); err == nil {
116+
c.projectConfigFile = ymlPath
117+
} else {
118+
// Otherwise default to codacy.yaml
119+
c.projectConfigFile = filepath.Join(c.localCodacyDirectory, "codacy.yaml")
120+
}
121+
114122
c.cliConfigFile = filepath.Join(c.localCodacyDirectory, "cli-config.yaml")
115123

116124
c.runtimes = make(map[string]*plugins.RuntimeInfo)

domain/patternConfiguration.go

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

88
type PatternDefinition struct {
9-
Id string `json:"id"`
10-
Category string `json:"category"`
11-
Level string `json:"level"`
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"`
1220
}
1321

1422
type PatternConfiguration struct {
1523
PatternDefinition PatternDefinition `json:"patternDefinition"`
1624
Parameters []ParameterConfiguration
25+
Enabled bool `json:"enabled"`
26+
IsCustom bool `json:"isCustom"`
1727
}

plugins/tool-utils_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ func TestGetSupportedTools(t *testing.T) {
167167
"pylint",
168168
"trivy",
169169
"dartanalyzer",
170+
"semgrep",
170171
},
171172
expectedError: false,
172173
},

plugins/tools/semgrep/plugin.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: semgrep
2+
description: Static Analysis Security Testing (SAST) tool
3+
runtime: python
4+
runtime_binaries:
5+
package_manager: python3
6+
execution: python3
7+
binaries:
8+
- name: python
9+
path: "venv/bin/python3"
10+
formatters:
11+
- name: json
12+
flag: "--json"
13+
output_options:
14+
file_flag: "--output"
15+
analysis_options:
16+
default_path: "."

0 commit comments

Comments
 (0)