Skip to content

Commit 333782d

Browse files
Feature: Add Semgrep tool (#82)
* Semgrep installation and running (#73) [Pluto-1390] * Semgrep config initilaization (#76) [Pluto-1391] * Refactor Semgrep analysis function to return error (#76)
1 parent 5bcc334 commit 333782d

File tree

16 files changed

+114532
-15
lines changed

16 files changed

+114532
-15
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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ codacy-cli
3131

3232
#Ignore cursor AI rules
3333
.cursor/rules/codacy.mdc
34+
35+
#Macos
36+
.DS_Store

cmd/analyze.go

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

225+
func runSemgrepAnalysis(workDirectory string, pathsToCheck []string, outputFile string, outputFormat string) error {
226+
semgrep := config.Config.Tools()["semgrep"]
227+
if semgrep == nil {
228+
log.Fatal("Semgrep tool configuration not found")
229+
}
230+
231+
return tools.RunSemgrep(workDirectory, semgrep, pathsToCheck, outputFile, outputFormat)
232+
}
233+
225234
var analyzeCmd = &cobra.Command{
226235
Use: "analyze",
227236
Short: "Runs all configured linters.",
@@ -312,6 +321,8 @@ func runTool(workDirectory string, toolName string, args []string, outputFile st
312321
return runPmdAnalysis(workDirectory, args, outputFile, outputFormat)
313322
case "pylint":
314323
return runPylintAnalysis(workDirectory, args, outputFile, outputFormat)
324+
case "semgrep":
325+
return runSemgrepAnalysis(workDirectory, args, outputFile, outputFormat)
315326
case "dartanalyzer":
316327
return runDartAnalyzer(workDirectory, args, outputFile, outputFormat)
317328
default:

cmd/init.go

Lines changed: 31 additions & 1 deletion
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()
@@ -266,7 +269,8 @@ func buildRepositoryConfigurationFiles(token string) error {
266269

267270
// Only generate config files for tools not using their own config file
268271
for _, tool := range configuredToolsWithUI {
269-
url := fmt.Sprintf("%s/api/v3/analysis/organizations/%s/%s/repositories/%s/tools/%s/patterns?enabled=true",
272+
273+
url := fmt.Sprintf("%s/api/v3/analysis/organizations/%s/%s/repositories/%s/tools/%s/patterns?enabled=true&limit=1000",
270274
CodacyApiBase,
271275
initFlags.provider,
272276
initFlags.organization,
@@ -396,6 +400,13 @@ func createToolFileConfigurations(tool tools.Tool, patternConfiguration []domain
396400
return fmt.Errorf("failed to create Dart Analyzer config: %v", err)
397401
}
398402
}
403+
case Semgrep:
404+
if len(patternConfiguration) > 0 {
405+
err := createSemgrepConfigFile(patternConfiguration, toolsConfigDir)
406+
if err != nil {
407+
return fmt.Errorf("failed to create Semgrep config: %v", err)
408+
}
409+
}
399410
}
400411
return nil
401412
}
@@ -456,6 +467,24 @@ func createDefaultEslintConfigFile(toolsConfigDir string) error {
456467
return os.WriteFile(filepath.Join(toolsConfigDir, "eslint.config.mjs"), []byte(content), utils.DefaultFilePerms)
457468
}
458469

470+
// SemgrepRulesFile represents the structure of the rules.yaml file
471+
type SemgrepRulesFile struct {
472+
Rules []map[string]interface{} `yaml:"rules"`
473+
}
474+
475+
// createSemgrepConfigFile creates a semgrep.yaml configuration file based on the API configuration
476+
func createSemgrepConfigFile(config []domain.PatternConfiguration, toolsConfigDir string) error {
477+
// Use the refactored function from tools package
478+
configData, err := tools.GetSemgrepConfig(config)
479+
480+
if err != nil {
481+
return fmt.Errorf("failed to create Semgrep config: %v", err)
482+
}
483+
484+
// Write to file
485+
return os.WriteFile(filepath.Join(toolsConfigDir, "semgrep.yaml"), configData, utils.DefaultFilePerms)
486+
}
487+
459488
// cleanConfigDirectory removes all previous configuration files in the tools-configs directory
460489
func cleanConfigDirectory(toolsConfigDir string) error {
461490
// Check if directory exists
@@ -489,4 +518,5 @@ const (
489518
PMD string = "9ed24812-b6ee-4a58-9004-0ed183c45b8f"
490519
PyLint string = "31677b6d-4ae0-4f56-8041-606a8d7a8e61"
491520
DartAnalyzer string = "d203d615-6cf1-41f9-be5f-e2f660f7850f"
521+
Semgrep string = "6792c561-236d-41b7-ba5e-9d6bee0d548b"
492522
)

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)