diff --git a/.codacy/codacy.yaml b/.codacy/codacy.yaml index 9929d638..0be11e4e 100644 --- a/.codacy/codacy.yaml +++ b/.codacy/codacy.yaml @@ -10,6 +10,6 @@ tools: - pmd@6.55.0 - pylint@3.3.9 - revive@1.12.0 - - semgrep@1.78.0 - - trivy@0.66.0 + - opengrep@1.16.2 + - trivy@0.69.3 - dartanalyzer@3.7.2 diff --git a/cmd/analyze.go b/cmd/analyze.go index 234c1c6b..1ead9705 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -273,7 +273,7 @@ var versionedToolNames = map[string]map[int]string{ var simpleToolAliases = map[string]string{ "lizard": "Lizard", - "semgrep": "Semgrep", + "opengrep": "Opengrep", "pylint": "pylintpython3", "trivy": "Trivy", } @@ -405,9 +405,9 @@ func runToolByName(toolName string, workDirectory string, pathsToCheck []string, case "dartanalyzer": binaryPath := tool.Binaries[tool.Runtime] return tools.RunDartAnalyzer(workDirectory, tool.InstallDir, binaryPath, pathsToCheck, outputFile, outputFormat) - case "semgrep": + case "opengrep": binaryPath := tool.Binaries[toolName] - return tools.RunSemgrep(workDirectory, binaryPath, pathsToCheck, outputFile, outputFormat) + return tools.RunOpengrep(workDirectory, binaryPath, pathsToCheck, outputFile, outputFormat) case "lizard": binaryPath := tool.Binaries[tool.Runtime] return lizard.RunLizard(workDirectory, binaryPath, pathsToCheck, outputFile, outputFormat) diff --git a/cmd/analyze_integration_test.go b/cmd/analyze_integration_test.go index 1e593ad7..a2f4d107 100644 --- a/cmd/analyze_integration_test.go +++ b/cmd/analyze_integration_test.go @@ -114,7 +114,7 @@ func TestToolConfigFileNameMapCompleteness(t *testing.T) { "pmd": constants.PMDConfigFileName, "pylint": constants.PylintConfigFileName, "dartanalyzer": constants.DartAnalyzerConfigFileName, - "semgrep": constants.SemgrepConfigFileName, + "opengrep": constants.OpengrepConfigFileName, "revive": constants.ReviveConfigFileName, "lizard": constants.LizardConfigFileName, } diff --git a/cmd/analyze_test.go b/cmd/analyze_test.go index 636ea550..d40703d3 100644 --- a/cmd/analyze_test.go +++ b/cmd/analyze_test.go @@ -449,7 +449,7 @@ func TestToolConfigFileNameMap(t *testing.T) { "pmd": constants.PMDConfigFileName, "pylint": constants.PylintConfigFileName, "dartanalyzer": constants.DartAnalyzerConfigFileName, - "semgrep": constants.SemgrepConfigFileName, + "opengrep": constants.OpengrepConfigFileName, "revive": constants.ReviveConfigFileName, "lizard": constants.LizardConfigFileName, } diff --git a/cmd/configsetup/tool_creators.go b/cmd/configsetup/tool_creators.go index 6674389a..6e67ff57 100644 --- a/cmd/configsetup/tool_creators.go +++ b/cmd/configsetup/tool_creators.go @@ -24,7 +24,7 @@ var toolConfigRegistry = map[string]ToolConfigCreator{ domain.PMD7: &pmd7ConfigCreator{}, domain.PyLint: &pylintConfigCreator{}, domain.DartAnalyzer: &dartAnalyzerConfigCreator{}, - domain.Semgrep: &semgrepConfigCreator{}, + domain.Opengrep: &opengrepConfigCreator{}, domain.Lizard: &lizardConfigCreator{}, domain.Revive: &reviveConfigCreator{}, } @@ -121,23 +121,23 @@ func (d *dartAnalyzerConfigCreator) GetConfigFileName() string { } func (d *dartAnalyzerConfigCreator) GetToolName() string { return "Dart Analyzer" } -// semgrepConfigCreator implements ToolConfigCreator for Semgrep -type semgrepConfigCreator struct{} +// opengrepConfigCreator implements ToolConfigCreator for Opengrep +type opengrepConfigCreator struct{} -func (s *semgrepConfigCreator) CreateConfig(toolsConfigDir string, patterns []domain.PatternConfiguration) error { - configData, err := tools.GetSemgrepConfig(patterns) +func (s *opengrepConfigCreator) CreateConfig(toolsConfigDir string, patterns []domain.PatternConfiguration) error { + configData, err := tools.GetOpengrepConfig(patterns) if err != nil { - return fmt.Errorf("failed to create Semgrep config: %v", err) + return fmt.Errorf("failed to create Opengrep config: %v", err) } - err = writeConfigFile(filepath.Join(toolsConfigDir, constants.SemgrepConfigFileName), configData) + err = writeConfigFile(filepath.Join(toolsConfigDir, constants.OpengrepConfigFileName), configData) if err == nil { - fmt.Println("Semgrep configuration created based on Codacy settings") + fmt.Println("Opengrep configuration created based on Codacy settings") } return err } -func (s *semgrepConfigCreator) GetConfigFileName() string { return constants.SemgrepConfigFileName } -func (s *semgrepConfigCreator) GetToolName() string { return "Semgrep" } +func (s *opengrepConfigCreator) GetConfigFileName() string { return constants.OpengrepConfigFileName } +func (s *opengrepConfigCreator) GetToolName() string { return "Opengrep" } // lizardConfigCreator implements ToolConfigCreator for Lizard type lizardConfigCreator struct{} diff --git a/cmd/init_test.go b/cmd/init_test.go index aad466a4..d7ca61a2 100644 --- a/cmd/init_test.go +++ b/cmd/init_test.go @@ -25,7 +25,7 @@ func TestConfigFileTemplate(t *testing.T) { "node@22.2.0", "python@3.11.11", "eslint@8.57.0", - "trivy@0.66.0", + "trivy@0.69.3", "pylint@3.3.6", "pmd@7.11.0", }, diff --git a/cmd/upload.go b/cmd/upload.go index 261b3133..1aa612be 100644 --- a/cmd/upload.go +++ b/cmd/upload.go @@ -55,7 +55,7 @@ var sarifShortNameMap = map[string]string{ "Trivy": "trivy", "Pylint": "pylintpython3", "dartanalyzer": "dartanalyzer", - "Semgrep": "semgrep", + "Opengrep": "opengrep", "Lizard": "lizard", "revive": "revive", } diff --git a/config/tools-installer.go b/config/tools-installer.go index 6d5aa861..0efd0a69 100644 --- a/config/tools-installer.go +++ b/config/tools-installer.go @@ -7,6 +7,7 @@ import ( "codacy/cli-v2/utils" "codacy/cli-v2/utils/logger" "fmt" + "io" "log" "os" "os/exec" @@ -297,29 +298,43 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { return fmt.Errorf("failed to create installation directory: %w", err) } - // Extract based on file extension - logger.Debug("Extracting tool", logrus.Fields{ - "tool": toolInfo.Name, - "version": toolInfo.Version, - "fileName": fileName, - "extractDirectory": toolInfo.InstallDir, - }) + isArchive := strings.HasSuffix(fileName, ".zip") || strings.HasSuffix(fileName, ".tar.gz") || strings.HasSuffix(fileName, ".tgz") - if strings.HasSuffix(fileName, ".zip") { - err = utils.ExtractZip(file.Name(), toolInfo.InstallDir) - } else { - err = utils.ExtractTarGz(file, toolInfo.InstallDir) - } + if isArchive { + // Extract based on file extension + logger.Debug("Extracting tool", logrus.Fields{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + "fileName": fileName, + "extractDirectory": toolInfo.InstallDir, + }) - if err != nil { - return fmt.Errorf("failed to extract tool: %w", err) - } + if strings.HasSuffix(fileName, ".zip") { + err = utils.ExtractZip(file.Name(), toolInfo.InstallDir) + } else { + err = utils.ExtractTarGz(file, toolInfo.InstallDir) + } + + if err != nil { + return fmt.Errorf("failed to extract tool: %w", err) + } - // Make sure all binaries are executable - for _, binaryPath := range toolInfo.Binaries { - err = os.Chmod(filepath.Join(toolInfo.InstallDir, filepath.Base(binaryPath)), constants.DefaultDirPerms) - if err != nil && !os.IsNotExist(err) { - return fmt.Errorf("failed to make binary executable: %w", err) + // Make sure all binaries are executable + for _, binaryPath := range toolInfo.Binaries { + err = os.Chmod(filepath.Join(toolInfo.InstallDir, filepath.Base(binaryPath)), constants.DefaultDirPerms) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to make binary executable: %w", err) + } + } + } else { + // Bare binary — copy directly to the binary destination path + logger.Debug("Installing bare binary", logrus.Fields{ + "tool": toolInfo.Name, + "version": toolInfo.Version, + "downloadPath": downloadPath, + }) + if err = installBareBinary(downloadPath, toolInfo); err != nil { + return fmt.Errorf("failed to install binary: %w", err) } } @@ -330,6 +345,44 @@ func installDownloadBasedTool(toolInfo *plugins.ToolInfo) error { return nil } +// installBareBinary copies a downloaded bare binary to its destination path and makes it executable. +func installBareBinary(downloadPath string, toolInfo *plugins.ToolInfo) error { + var destPath string + for _, p := range toolInfo.Binaries { + destPath = p + break + } + if destPath == "" { + return fmt.Errorf("no binary destination defined for tool %s", toolInfo.Name) + } + + if err := os.MkdirAll(filepath.Dir(destPath), constants.DefaultDirPerms); err != nil { + return fmt.Errorf("failed to create binary directory: %w", err) + } + + src, err := os.Open(downloadPath) + if err != nil { + return fmt.Errorf("failed to open downloaded binary: %w", err) + } + defer src.Close() + + dst, err := os.Create(destPath) + if err != nil { + return fmt.Errorf("failed to create binary file: %w", err) + } + defer dst.Close() + + if _, err = io.Copy(dst, src); err != nil { + return fmt.Errorf("failed to copy binary: %w", err) + } + + if err = os.Chmod(destPath, constants.DefaultDirPerms); err != nil { + return fmt.Errorf("failed to make binary executable: %w", err) + } + + return nil +} + func installPythonTool(name string, toolInfo *plugins.ToolInfo) error { logger.Debug("Starting Python tool installation", logrus.Fields{ "tool": toolInfo.Name, diff --git a/constants/tool_configs.go b/constants/tool_configs.go index ad8b01f7..cf03f49d 100644 --- a/constants/tool_configs.go +++ b/constants/tool_configs.go @@ -12,7 +12,7 @@ const ( PMDConfigFileName = "ruleset.xml" PylintConfigFileName = "pylint.rc" DartAnalyzerConfigFileName = "analysis_options.yaml" - SemgrepConfigFileName = "semgrep.yaml" + OpengrepConfigFileName = "semgrep.yaml" ReviveConfigFileName = "revive.toml" LizardConfigFileName = "lizard.yaml" ) @@ -24,7 +24,7 @@ var ToolConfigFileNames = map[string]string{ "pmd": PMDConfigFileName, "pylint": PylintConfigFileName, "dartanalyzer": DartAnalyzerConfigFileName, - "semgrep": SemgrepConfigFileName, + "opengrep": OpengrepConfigFileName, "revive": ReviveConfigFileName, "lizard": LizardConfigFileName, } diff --git a/domain/tool.go b/domain/tool.go index ecb18cf6..0591fe02 100644 --- a/domain/tool.go +++ b/domain/tool.go @@ -28,7 +28,7 @@ const ( PMD7 string = "ed7e8287-707d-485a-a0cb-e211004432c2" PyLint string = "31677b6d-4ae0-4f56-8041-606a8d7a8e61" DartAnalyzer string = "d203d615-6cf1-41f9-be5f-e2f660f7850f" - Semgrep string = "6792c561-236d-41b7-ba5e-9d6bee0d548b" + Opengrep string = "6792c561-236d-41b7-ba5e-9d6bee0d548b" Lizard string = "76348462-84b3-409a-90d3-955e90abfb87" Revive string = "bd81d1f4-1406-402d-9181-1274ee09f1aa" ) @@ -48,6 +48,6 @@ var SupportedToolsMetadata = map[string]ToolInfo{ Trivy: {Name: "trivy", Priority: 0}, DartAnalyzer: {Name: "dartanalyzer", Priority: 0}, Lizard: {Name: "lizard", Priority: 0}, - Semgrep: {Name: "semgrep", Priority: 0}, + Opengrep: {Name: "opengrep", Priority: 0}, Revive: {Name: "revive", Priority: 0}, } diff --git a/integration-tests/config-discover/expected/codacy.yaml b/integration-tests/config-discover/expected/codacy.yaml index 199dd6da..53b46cdc 100644 --- a/integration-tests/config-discover/expected/codacy.yaml +++ b/integration-tests/config-discover/expected/codacy.yaml @@ -7,7 +7,7 @@ tools: - dartanalyzer@3.7.2 - eslint@8.57.0 - lizard@1.17.31 + - opengrep@1.16.2 - pmd@7.11.0 - pylint@3.3.6 - - semgrep@1.78.0 - - trivy@0.66.0 + - trivy@0.69.3 diff --git a/integration-tests/config-discover/expected/tools-configs/languages-config.yaml b/integration-tests/config-discover/expected/tools-configs/languages-config.yaml index 6e686c11..9d685b32 100644 --- a/integration-tests/config-discover/expected/tools-configs/languages-config.yaml +++ b/integration-tests/config-discover/expected/tools-configs/languages-config.yaml @@ -23,11 +23,11 @@ tools: languages: [Go] extensions: [.go] files: [] - - name: semgrep + - name: opengrep languages: [Apex, C, CPP, CSharp, Dockerfile, Go, Java, Javascript, Kotlin, PHP, PLSQL, Python, Ruby, Rust, SQL, Scala, Shell, Swift, Terraform, TypeScript, YAML] - extensions: [.bash, .c, .cc, .cls, .cpp, .cs, .cxx, .dockerfile, .fnc, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .jsx, .kt, .kts, .mjs, .opal, .pck, .php, .pkb, .pkh, .pks, .plb, .pld, .plh, .pls, .podspec, .prc, .py, .rake, .rb, .rlib, .rs, .scala, .sh, .sql, .swift, .tf, .tpb, .tps, .trg, .trigger, .ts, .tsx, .tyb, .typ, .vue, .yaml, .yml] + extensions: [.bash, .c, .cc, .cls, .cpp, .cs, .cxx, .dockerfile, .env, .fnc, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .jsx, .kt, .kts, .mjs, .opal, .pck, .php, .pkb, .pkh, .pks, .plb, .pld, .plh, .pls, .podspec, .prc, .py, .rake, .rb, .rlib, .rs, .scala, .sh, .sql, .swift, .tf, .tpb, .tps, .trg, .trigger, .ts, .tsx, .tyb, .typ, .vue, .yaml, .yml] files: [] - name: trivy languages: [C, CPP, CSharp, Dart, Dockerfile, Elixir, Go, JSON, Java, Javascript, PHP, Python, Ruby, Rust, Scala, Swift, Terraform, TypeScript, XML, YAML] - extensions: [.c, .cc, .cpp, .cs, .cxx, .dart, .dockerfile, .ex, .exs, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .json, .jsx, .mjs, .opal, .php, .podspec, .pom, .py, .rake, .rb, .rlib, .rs, .scala, .swift, .tf, .ts, .tsx, .vue, .wsdl, .xml, .xsl, .yaml, .yml] - files: [.deps.json, Berksfile, Capfile, Cargo.lock, Cheffile, Directory.Packages.props, Dockerfile, Fastfile, Gemfile, Gemfile.lock, Guardfile, Package.resolved, Packages.props, Pipfile.lock, Podfile, Podfile.lock, Rakefile, Thorfile, Vagabondfile, Vagrantfile, build.sbt.lock, composer.lock, conan.lock, config.ru, go.mod, gradle.lockfile, mix.lock, package-lock.json, package.json, packages.config, packages.lock.json, pnpm-lock.yaml, poetry.lock, pom.xml, pubspec.lock, requirements.txt, uv.lock, yarn.lock] + extensions: [.c, .cc, .cpp, .cs, .cxx, .dart, .dockerfile, .env, .ex, .exs, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .json, .jsx, .mjs, .opal, .php, .podspec, .pom, .py, .rake, .rb, .rlib, .rs, .scala, .swift, .tf, .ts, .tsx, .vue, .wsdl, .xml, .xsl, .yaml, .yml] + files: [.deps.json, .env, .env.dev, .env.development, .env.prod, .env.production, .env.staging, Berksfile, Capfile, Cargo.lock, Cheffile, Directory.Packages.props, Dockerfile, Fastfile, Gemfile, Gemfile.lock, Guardfile, Package.resolved, Packages.props, Pipfile.lock, Podfile, Podfile.lock, Rakefile, Thorfile, Vagabondfile, Vagrantfile, build.sbt.lock, composer.lock, conan.lock, config.ru, go.mod, gradle.lockfile, mix.lock, package-lock.json, package.json, packages.config, packages.lock.json, pnpm-lock.yaml, poetry.lock, pom.xml, pubspec.lock, requirements.txt, uv.lock, yarn.lock] diff --git a/integration-tests/init-with-token/expected/codacy.yaml b/integration-tests/init-with-token/expected/codacy.yaml index d104769b..18fae4b6 100644 --- a/integration-tests/init-with-token/expected/codacy.yaml +++ b/integration-tests/init-with-token/expected/codacy.yaml @@ -5,7 +5,7 @@ runtimes: tools: - eslint@8.57.0 - lizard@1.17.31 + - opengrep@1.16.2 - pmd@6.55.0 - pylint@3.3.9 - - semgrep@1.78.0 - - trivy@0.66.0 + - trivy@0.69.3 diff --git a/integration-tests/init-with-token/expected/tools-configs/languages-config.yaml b/integration-tests/init-with-token/expected/tools-configs/languages-config.yaml index 71f6d25f..0bf11561 100644 --- a/integration-tests/init-with-token/expected/tools-configs/languages-config.yaml +++ b/integration-tests/init-with-token/expected/tools-configs/languages-config.yaml @@ -15,7 +15,7 @@ tools: languages: [Python] extensions: [.py] files: [] - - name: semgrep + - name: opengrep languages: [Java, Javascript, Python] extensions: [.java, .js, .jsm, .jsx, .mjs, .py, .vue] files: [] diff --git a/integration-tests/init-without-token/expected/codacy.yaml b/integration-tests/init-without-token/expected/codacy.yaml index 15365c77..e723e133 100644 --- a/integration-tests/init-without-token/expected/codacy.yaml +++ b/integration-tests/init-without-token/expected/codacy.yaml @@ -8,8 +8,8 @@ tools: - dartanalyzer@3.7.2 - eslint@8.57.0 - lizard@1.17.31 + - opengrep@1.16.2 - pmd@7.11.0 - pylint@3.3.6 - revive@1.7.0 - - semgrep@1.78.0 - - trivy@0.66.0 + - trivy@0.69.3 diff --git a/integration-tests/init-without-token/expected/tools-configs/languages-config.yaml b/integration-tests/init-without-token/expected/tools-configs/languages-config.yaml index 0998dce0..8981a44c 100644 --- a/integration-tests/init-without-token/expected/tools-configs/languages-config.yaml +++ b/integration-tests/init-without-token/expected/tools-configs/languages-config.yaml @@ -23,11 +23,11 @@ tools: languages: [Go] extensions: [.go] files: [] - - name: semgrep + - name: opengrep languages: [Apex, C, CPP, CSharp, Dockerfile, Go, Java, Javascript, Kotlin, PHP, PLSQL, Python, Ruby, Rust, SQL, Scala, Shell, Swift, Terraform, TypeScript, YAML] - extensions: [.bash, .c, .cc, .cls, .cpp, .cs, .cxx, .dockerfile, .fnc, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .jsx, .kt, .kts, .mjs, .opal, .pck, .php, .pkb, .pkh, .pks, .plb, .pld, .plh, .pls, .podspec, .prc, .py, .rake, .rb, .rlib, .rs, .scala, .sh, .sql, .swift, .tf, .tpb, .tps, .trg, .trigger, .ts, .tsx, .tyb, .typ, .vue, .yaml, .yml] + extensions: [.bash, .c, .cc, .cls, .cpp, .cs, .cxx, .dockerfile, .env, .fnc, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .jsx, .kt, .kts, .mjs, .opal, .pck, .php, .pkb, .pkh, .pks, .plb, .pld, .plh, .pls, .podspec, .prc, .py, .rake, .rb, .rlib, .rs, .scala, .sh, .sql, .swift, .tf, .tpb, .tps, .trg, .trigger, .ts, .tsx, .tyb, .typ, .vue, .yaml, .yml] files: [] - name: trivy languages: [C, CPP, CSharp, Dart, Dockerfile, Elixir, Go, JSON, Java, Javascript, PHP, Python, Ruby, Rust, Scala, Swift, Terraform, TypeScript, XML, YAML] - extensions: [.c, .cc, .cpp, .cs, .cxx, .dart, .dockerfile, .ex, .exs, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .json, .jsx, .mjs, .opal, .php, .podspec, .pom, .py, .rake, .rb, .rlib, .rs, .scala, .swift, .tf, .ts, .tsx, .vue, .wsdl, .xml, .xsl, .yaml, .yml] - files: [.deps.json, Berksfile, Capfile, Cargo.lock, Cheffile, Directory.Packages.props, Dockerfile, Fastfile, Gemfile, Gemfile.lock, Guardfile, Package.resolved, Packages.props, Pipfile.lock, Podfile, Podfile.lock, Rakefile, Thorfile, Vagabondfile, Vagrantfile, build.sbt.lock, composer.lock, conan.lock, config.ru, go.mod, gradle.lockfile, mix.lock, package-lock.json, package.json, packages.config, packages.lock.json, pnpm-lock.yaml, poetry.lock, pom.xml, pubspec.lock, requirements.txt, uv.lock, yarn.lock] \ No newline at end of file + extensions: [.c, .cc, .cpp, .cs, .cxx, .dart, .dockerfile, .env, .ex, .exs, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .json, .jsx, .mjs, .opal, .php, .podspec, .pom, .py, .rake, .rb, .rlib, .rs, .scala, .swift, .tf, .ts, .tsx, .vue, .wsdl, .xml, .xsl, .yaml, .yml] + files: [.deps.json, .env, .env.dev, .env.development, .env.prod, .env.production, .env.staging, Berksfile, Capfile, Cargo.lock, Cheffile, Directory.Packages.props, Dockerfile, Fastfile, Gemfile, Gemfile.lock, Guardfile, Package.resolved, Packages.props, Pipfile.lock, Podfile, Podfile.lock, Rakefile, Thorfile, Vagabondfile, Vagrantfile, build.sbt.lock, composer.lock, conan.lock, config.ru, go.mod, gradle.lockfile, mix.lock, package-lock.json, package.json, packages.config, packages.lock.json, pnpm-lock.yaml, poetry.lock, pom.xml, pubspec.lock, requirements.txt, uv.lock, yarn.lock] \ No newline at end of file diff --git a/plugins/shared.go b/plugins/shared.go index b518b81a..ccc66533 100644 --- a/plugins/shared.go +++ b/plugins/shared.go @@ -27,6 +27,7 @@ type DownloadConfig struct { FileNameTemplate string `yaml:"file_name_template"` Extension ExtensionConfig `yaml:"extension"` ArchMapping map[string]string `yaml:"arch_mapping"` + OSArchMapping map[string]string `yaml:"os_arch_mapping"` OSMapping map[string]string `yaml:"os_mapping"` ReleaseVersion string `yaml:"release_version,omitempty"` } diff --git a/plugins/tool-utils.go b/plugins/tool-utils.go index e574e0b9..9ec28e83 100644 --- a/plugins/tool-utils.go +++ b/plugins/tool-utils.go @@ -159,8 +159,12 @@ func ProcessTools(configs []ToolConfig, toolDir string, runtimes map[string]*Run // Handle download configuration for directly downloaded tools if pluginConfig.Download.URLTemplate != "" { - // Get the mapped architecture + // Get the mapped architecture, with optional OS-specific override mappedArch := GetMappedArch(pluginConfig.Download.ArchMapping, runtime.GOARCH) + osArchKey := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH) + if override, ok := pluginConfig.Download.OSArchMapping[osArchKey]; ok { + mappedArch = override + } // Get the mapped OS mappedOS := GetMappedOS(pluginConfig.Download.OSMapping, runtime.GOOS) diff --git a/plugins/tool-utils_test.go b/plugins/tool-utils_test.go index 50b1c028..5895aa76 100644 --- a/plugins/tool-utils_test.go +++ b/plugins/tool-utils_test.go @@ -169,7 +169,7 @@ func TestGetSupportedTools(t *testing.T) { "pylint", "trivy", "dartanalyzer", - "semgrep", + "opengrep", "lizard", "codacy-enigma-cli", "revive", diff --git a/plugins/tools/opengrep/embedded/opengrep.go b/plugins/tools/opengrep/embedded/opengrep.go new file mode 100644 index 00000000..47a3cca0 --- /dev/null +++ b/plugins/tools/opengrep/embedded/opengrep.go @@ -0,0 +1,17 @@ +// Package embedded provides access to embedded Opengrep rules. +package embedded + +import "embed" + +//go:embed rules.yaml +var rulesFS embed.FS + +// GetOpengrepRules returns the embedded Opengrep rules. +// Opengrep is compatible with the semgrep rule format, so the same rules are used. +func GetOpengrepRules() []byte { + data, err := rulesFS.ReadFile("rules.yaml") + if err != nil { + panic(err) // This should never happen as the file is embedded + } + return data +} diff --git a/plugins/tools/semgrep/embedded/rules.yaml b/plugins/tools/opengrep/embedded/rules.yaml similarity index 100% rename from plugins/tools/semgrep/embedded/rules.yaml rename to plugins/tools/opengrep/embedded/rules.yaml diff --git a/plugins/tools/opengrep/plugin.yaml b/plugins/tools/opengrep/plugin.yaml new file mode 100644 index 00000000..8a9fc326 --- /dev/null +++ b/plugins/tools/opengrep/plugin.yaml @@ -0,0 +1,28 @@ +name: opengrep +description: Opengrep is an open-source static analysis tool and community fork of Semgrep for finding bugs and enforcing code standards. +default_version: 1.16.2 +download: + url_template: "https://github.com/opengrep/opengrep/releases/download/v{{.Version}}/opengrep_{{.OS}}_{{.Arch}}{{.Extension}}" + file_name_template: "opengrep_{{.OS}}_{{.Arch}}" + extension: + windows: ".exe" + default: "" + arch_mapping: + "amd64": "x86" + "arm64": "arm64" + os_arch_mapping: + "linux_arm64": "aarch64" + os_mapping: + "darwin": "osx" + "linux": "manylinux" + "windows": "windows" +binaries: + - name: opengrep + path: "opengrep" +formatters: + - name: json + flag: "--json" +output_options: + file_flag: "--output" +analysis_options: + default_path: "." diff --git a/plugins/tools/opengrep/test/expected.sarif b/plugins/tools/opengrep/test/expected.sarif new file mode 100644 index 00000000..c787de20 --- /dev/null +++ b/plugins/tools/opengrep/test/expected.sarif @@ -0,0 +1,197 @@ +{ + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": [ + { + "invocations": [ + { + "executionSuccessful": true, + "toolExecutionNotifications": [] + } + ], + "results": [ + { + "fingerprints": { + "matchBasedId/v1": "d68b4b5aa90adf170c15bd2f15e46001e617fb546c1f75c00cb31e0294e948f00f38ae86c9dc5b943eb415eb6b1b152f55a6c8e1ce45174821189099b69c499a_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "test_file.py", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 26, + "endLine": 14, + "snippet": { + "text": " user_input = \"ls -la\"" + }, + "startColumn": 5, + "startLine": 14 + } + } + } + ], + "message": { + "text": "Hardcoded password detected" + }, + "properties": {}, + "ruleId": "codacy.tools-configs.python.lang.security.audit.hardcoded-password.hardcoded-password" + }, + { + "fingerprints": { + "matchBasedId/v1": "fb709112486f440290f4ceb370b2530e2dc80ac719854debf8ef1cd92d493ff791afaadf0240b41f9365d69fef012c8b8a04e2a1b67ff651ff621d8c93d1bfda_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "test_file.py", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 37, + "endLine": 20, + "snippet": { + "text": " password = \"mysecretpassword123\" # opengrep: python.lang.security.audit.hardcoded-password.hardcoded-password" + }, + "startColumn": 5, + "startLine": 20 + } + } + } + ], + "message": { + "text": "Hardcoded password detected" + }, + "properties": {}, + "ruleId": "codacy.tools-configs.python.lang.security.audit.hardcoded-password.hardcoded-password" + }, + { + "fingerprints": { + "matchBasedId/v1": "ab899bcac588e9ca6eb62e2f3622c585458008ecbd31be21c538a80b2f34238826af6d34710506d190469ec9e2e6068fd0dc05f2f1e483fcc32dfa5dbce29a11_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "test_file.py", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 43, + "endLine": 26, + "snippet": { + "text": " data = b\"cos\\nsystem\\n(S'ls -la'\\ntR.\"" + }, + "startColumn": 5, + "startLine": 26 + } + } + } + ], + "message": { + "text": "Hardcoded password detected" + }, + "properties": {}, + "ruleId": "codacy.tools-configs.python.lang.security.audit.hardcoded-password.hardcoded-password" + }, + { + "fingerprints": { + "matchBasedId/v1": "5c6d33cba2da3f1092652370087a5fe5eb394bc1675e593c3cef420f2a26e97bea82e0caa8741a5c13a09ca85f1e1015deb2928958516de72c2fcddb84acc215_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "test_file.py", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 26, + "endLine": 15, + "snippet": { + "text": " os.system(user_input) # opengrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true" + }, + "startColumn": 5, + "startLine": 15 + } + } + } + ], + "message": { + "text": "Unsafe command execution with os.system" + }, + "properties": {}, + "ruleId": "codacy.tools-configs.python.lang.security.audit.os-system.os-system" + }, + { + "fingerprints": { + "matchBasedId/v1": "129aec3858c4c532da6214fac11e10c87bc7789d07f1651dc6e82f1d62ccfb29cc6e3fdd44320f3b06bad930ffa2bf454f75d03768ebfc8aed12191cbc3496b7_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "test_file.py", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 23, + "endLine": 27, + "snippet": { + "text": " pickle.loads(data) # opengrep: python.lang.security.audit.pickle.avoid-pickle" + }, + "startColumn": 5, + "startLine": 27 + } + } + } + ], + "message": { + "text": "Unsafe deserialization with pickle" + }, + "properties": {}, + "ruleId": "codacy.tools-configs.python.lang.security.audit.pickle.avoid-pickle" + }, + { + "fingerprints": { + "matchBasedId/v1": "912dfe82da41aeee9a4a4c9c195d94f60e63458f1094080e0e24585c6f7894c5822ca61ad89cd45cd56d30f0016802a9e87805d429e4fd751c6917e003c3c3f7_0" + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "test_file.py", + "uriBaseId": "%SRCROOT%" + }, + "region": { + "endColumn": 43, + "endLine": 16, + "snippet": { + "text": " subprocess.run(user_input, shell=True) # opengrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true" + }, + "startColumn": 5, + "startLine": 16 + } + } + } + ], + "message": { + "text": "Unsafe command execution with shell=True" + }, + "properties": {}, + "ruleId": "codacy.tools-configs.python.lang.security.audit.subprocess-shell-true.subprocess-shell-true" + } + ], + "tool": { + "driver": { + "name": "Opengrep OSS", + "rules": null, + "semanticVersion": "1.16.2" + } + } + } + ], + "version": "2.1.0" +} \ No newline at end of file diff --git a/plugins/tools/semgrep/test/src/.codacy/codacy.yaml b/plugins/tools/opengrep/test/src/.codacy/codacy.yaml similarity index 63% rename from plugins/tools/semgrep/test/src/.codacy/codacy.yaml rename to plugins/tools/opengrep/test/src/.codacy/codacy.yaml index f56b8332..2ddb1f52 100644 --- a/plugins/tools/semgrep/test/src/.codacy/codacy.yaml +++ b/plugins/tools/opengrep/test/src/.codacy/codacy.yaml @@ -1,4 +1,4 @@ runtimes: - python@3.11.11 tools: - - semgrep@1.78.0 \ No newline at end of file + - opengrep@1.16.2 diff --git a/plugins/tools/semgrep/test/src/.codacy/tools-configs/semgrep.yml b/plugins/tools/opengrep/test/src/.codacy/tools-configs/semgrep.yml similarity index 100% rename from plugins/tools/semgrep/test/src/.codacy/tools-configs/semgrep.yml rename to plugins/tools/opengrep/test/src/.codacy/tools-configs/semgrep.yml diff --git a/plugins/tools/semgrep/test/src/test_file.py b/plugins/tools/opengrep/test/src/test_file.py similarity index 53% rename from plugins/tools/semgrep/test/src/test_file.py rename to plugins/tools/opengrep/test/src/test_file.py index 74a543c4..4031aaeb 100644 --- a/plugins/tools/semgrep/test/src/test_file.py +++ b/plugins/tools/opengrep/test/src/test_file.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """ -Test file for semgrep analysis +Test file for opengrep analysis """ import os @@ -12,19 +12,19 @@ def unsafe_command_execution(): """Function with unsafe command execution""" user_input = "ls -la" - os.system(user_input) # semgrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true - subprocess.run(user_input, shell=True) # semgrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true + os.system(user_input) # opengrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true + subprocess.run(user_input, shell=True) # opengrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true def hardcoded_password(): """Function with hardcoded password""" - password = "mysecretpassword123" # semgrep: python.lang.security.audit.hardcoded-password.hardcoded-password + password = "mysecretpassword123" # opengrep: python.lang.security.audit.hardcoded-password.hardcoded-password return password def unsafe_deserialization(): """Function with unsafe deserialization""" import pickle data = b"cos\nsystem\n(S'ls -la'\ntR." - pickle.loads(data) # semgrep: python.lang.security.audit.pickle.avoid-pickle + pickle.loads(data) # opengrep: python.lang.security.audit.pickle.avoid-pickle def main(): unsafe_command_execution() @@ -32,4 +32,4 @@ def main(): unsafe_deserialization() if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/plugins/tools/semgrep/embedded/semgrep.go b/plugins/tools/semgrep/embedded/semgrep.go deleted file mode 100644 index ad25f336..00000000 --- a/plugins/tools/semgrep/embedded/semgrep.go +++ /dev/null @@ -1,16 +0,0 @@ -// Package embedded contains embedded files used by the tools package -package embedded - -import "embed" - -//go:embed rules.yaml -var rulesFS embed.FS - -// GetSemgrepRules returns the embedded Semgrep rules -func GetSemgrepRules() []byte { - data, err := rulesFS.ReadFile("rules.yaml") - if err != nil { - panic(err) // This should never happen as the file is embedded - } - return data -} diff --git a/plugins/tools/semgrep/plugin.yaml b/plugins/tools/semgrep/plugin.yaml deleted file mode 100644 index 58b773b0..00000000 --- a/plugins/tools/semgrep/plugin.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: semgrep -description: Semgrep is a fast, open-source, static analysis tool for finding bugs and enforcing code standards at editor, commit, and CI time. -default_version: 1.78.0 -runtime: python -runtime_binaries: - package_manager: python3 - execution: python3 -binaries: - - name: semgrep - path: "venv/bin/semgrep" -formatters: - - name: json - flag: "--json" -output_options: - file_flag: "--output" -analysis_options: - default_path: "." diff --git a/plugins/tools/semgrep/test/expected.sarif b/plugins/tools/semgrep/test/expected.sarif deleted file mode 100644 index a9786691..00000000 --- a/plugins/tools/semgrep/test/expected.sarif +++ /dev/null @@ -1,197 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", - "runs": [ - { - "invocations": [ - { - "executionSuccessful": true, - "toolExecutionNotifications": [] - } - ], - "results": [ - { - "fingerprints": { - "matchBasedId/v1": "d68b4b5aa90adf170c15bd2f15e46001e617fb546c1f75c00cb31e0294e948f00f38ae86c9dc5b943eb415eb6b1b152f55a6c8e1ce45174821189099b69c499a_0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "test_file.py", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "endColumn": 26, - "endLine": 14, - "snippet": { - "text": " user_input = \"ls -la\"" - }, - "startColumn": 5, - "startLine": 14 - } - } - } - ], - "message": { - "text": "Hardcoded password detected" - }, - "properties": {}, - "ruleId": "codacy.tools-configs.python.lang.security.audit.hardcoded-password.hardcoded-password" - }, - { - "fingerprints": { - "matchBasedId/v1": "5c6d33cba2da3f1092652370087a5fe5eb394bc1675e593c3cef420f2a26e97bea82e0caa8741a5c13a09ca85f1e1015deb2928958516de72c2fcddb84acc215_0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "test_file.py", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "endColumn": 26, - "endLine": 15, - "snippet": { - "text": " os.system(user_input) # semgrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true" - }, - "startColumn": 5, - "startLine": 15 - } - } - } - ], - "message": { - "text": "Unsafe command execution with os.system" - }, - "properties": {}, - "ruleId": "codacy.tools-configs.python.lang.security.audit.os-system.os-system" - }, - { - "fingerprints": { - "matchBasedId/v1": "912dfe82da41aeee9a4a4c9c195d94f60e63458f1094080e0e24585c6f7894c5822ca61ad89cd45cd56d30f0016802a9e87805d429e4fd751c6917e003c3c3f7_0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "test_file.py", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "endColumn": 43, - "endLine": 16, - "snippet": { - "text": " subprocess.run(user_input, shell=True) # semgrep: python.lang.security.audit.subprocess-shell-true.subprocess-shell-true" - }, - "startColumn": 5, - "startLine": 16 - } - } - } - ], - "message": { - "text": "Unsafe command execution with shell=True" - }, - "properties": {}, - "ruleId": "codacy.tools-configs.python.lang.security.audit.subprocess-shell-true.subprocess-shell-true" - }, - { - "fingerprints": { - "matchBasedId/v1": "fb709112486f440290f4ceb370b2530e2dc80ac719854debf8ef1cd92d493ff791afaadf0240b41f9365d69fef012c8b8a04e2a1b67ff651ff621d8c93d1bfda_0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "test_file.py", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "endColumn": 37, - "endLine": 20, - "snippet": { - "text": " password = \"mysecretpassword123\" # semgrep: python.lang.security.audit.hardcoded-password.hardcoded-password" - }, - "startColumn": 5, - "startLine": 20 - } - } - } - ], - "message": { - "text": "Hardcoded password detected" - }, - "properties": {}, - "ruleId": "codacy.tools-configs.python.lang.security.audit.hardcoded-password.hardcoded-password" - }, - { - "fingerprints": { - "matchBasedId/v1": "ab899bcac588e9ca6eb62e2f3622c585458008ecbd31be21c538a80b2f34238826af6d34710506d190469ec9e2e6068fd0dc05f2f1e483fcc32dfa5dbce29a11_0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "test_file.py", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "endColumn": 43, - "endLine": 26, - "snippet": { - "text": " data = b\"cos\\nsystem\\n(S'ls -la'\\ntR.\"" - }, - "startColumn": 5, - "startLine": 26 - } - } - } - ], - "message": { - "text": "Hardcoded password detected" - }, - "properties": {}, - "ruleId": "codacy.tools-configs.python.lang.security.audit.hardcoded-password.hardcoded-password" - }, - { - "fingerprints": { - "matchBasedId/v1": "129aec3858c4c532da6214fac11e10c87bc7789d07f1651dc6e82f1d62ccfb29cc6e3fdd44320f3b06bad930ffa2bf454f75d03768ebfc8aed12191cbc3496b7_0" - }, - "locations": [ - { - "physicalLocation": { - "artifactLocation": { - "uri": "test_file.py", - "uriBaseId": "%SRCROOT%" - }, - "region": { - "endColumn": 23, - "endLine": 27, - "snippet": { - "text": " pickle.loads(data) # semgrep: python.lang.security.audit.pickle.avoid-pickle" - }, - "startColumn": 5, - "startLine": 27 - } - } - } - ], - "message": { - "text": "Unsafe deserialization with pickle" - }, - "properties": {}, - "ruleId": "codacy.tools-configs.python.lang.security.audit.pickle.avoid-pickle" - } - ], - "tool": { - "driver": { - "name": "Semgrep OSS", - "rules": null, - "semanticVersion": "1.78.0" - } - } - } - ], - "version": "2.1.0" -} \ No newline at end of file diff --git a/plugins/tools/trivy/plugin.yaml b/plugins/tools/trivy/plugin.yaml index bb93a023..d1329a19 100644 --- a/plugins/tools/trivy/plugin.yaml +++ b/plugins/tools/trivy/plugin.yaml @@ -1,6 +1,6 @@ name: trivy description: Trivy is a comprehensive security scanner for containers and other artifacts. -default_version: 0.66.0 +default_version: 0.69.3 download: url_template: "https://github.com/aquasecurity/trivy/releases/download/v{{.Version}}/trivy_{{.Version}}_{{.OS}}-{{.Arch}}.{{.Extension}}" file_name_template: "trivy_{{.Version}}_{{.OS}}_{{.Arch}}" diff --git a/plugins/tools/trivy/test/expected.sarif b/plugins/tools/trivy/test/expected.sarif index e138915a..a568eb9b 100644 --- a/plugins/tools/trivy/test/expected.sarif +++ b/plugins/tools/trivy/test/expected.sarif @@ -1,322 +1,403 @@ { -"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", -"runs": [ - { - "columnKind": "utf16CodeUnits", - "originalUriBaseIds": { - "ROOTPATH": { - "uri": "file:///plugins/tools/trivy/test/src/" - } - }, - "results": [ - { - "level": "warning", - "locations": [ - { - "message": { - "text": "requirements.txt: django@1.11.29" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "requirements.txt", - "uriBaseId": "ROOTPATH" + "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", + "runs": [ + { + "columnKind": "utf16CodeUnits", + "originalUriBaseIds": { + "ROOTPATH": { + "uri": "file:///plugins/tools/trivy/test/src/" + } + }, + "results": [ + { + "level": "warning", + "locations": [ + { + "message": { + "text": "package-lock.json: ajv@6.12.6" }, - "region": { - "endColumn": 1, - "endLine": 1, - "startColumn": 1, - "startLine": 1 + "physicalLocation": { + "artifactLocation": { + "uri": "package-lock.json", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 316, + "startColumn": 1, + "startLine": 302 + } } } - } - ], - "message": { - "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2021-33203\nSeverity: MEDIUM\nFixed Version: 2.2.24, 3.1.12, 3.2.4\nLink: [CVE-2021-33203](https://avd.aquasec.com/nvd/cve-2021-33203)" + ], + "message": { + "text": "Package: ajv\nInstalled Version: 6.12.6\nVulnerability CVE-2025-69873\nSeverity: MEDIUM\nFixed Version: 8.18.0, 6.14.0\nLink: [CVE-2025-69873](https://avd.aquasec.com/nvd/cve-2025-69873)" + }, + "ruleId": "CVE-2025-69873", + "ruleIndex": 0 }, - "ruleId": "CVE-2021-33203", - "ruleIndex": 8 - }, - { - "level": "error", - "locations": [ - { - "message": { - "text": "requirements.txt: django@1.11.29" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "requirements.txt", - "uriBaseId": "ROOTPATH" + { + "level": "note", + "locations": [ + { + "message": { + "text": "package-lock.json: brace-expansion@1.1.11" }, - "region": { - "endColumn": 1, - "endLine": 1, - "startColumn": 1, - "startLine": 1 + "physicalLocation": { + "artifactLocation": { + "uri": "package-lock.json", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 357, + "startColumn": 1, + "startLine": 349 + } } } - } - ], - "message": { - "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2022-36359\nSeverity: HIGH\nFixed Version: 3.2.15, 4.0.7\nLink: [CVE-2022-36359](https://avd.aquasec.com/nvd/cve-2022-36359)" + ], + "message": { + "text": "Package: brace-expansion\nInstalled Version: 1.1.11\nVulnerability CVE-2025-5889\nSeverity: LOW\nFixed Version: 2.0.2, 1.1.12, 3.0.1, 4.0.1\nLink: [CVE-2025-5889](https://avd.aquasec.com/nvd/cve-2025-5889)" + }, + "ruleId": "CVE-2025-5889", + "ruleIndex": 1 }, - "ruleId": "CVE-2022-36359", - "ruleIndex": 5 - }, - { - "level": "error", - "locations": [ - { - "message": { - "text": "package-lock.json: cross-spawn@7.0.3" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "package-lock.json", - "uriBaseId": "ROOTPATH" + { + "level": "error", + "locations": [ + { + "message": { + "text": "package-lock.json: cross-spawn@7.0.3" }, - "region": { - "endColumn": 1, - "endLine": 527, - "startColumn": 1, - "startLine": 515 + "physicalLocation": { + "artifactLocation": { + "uri": "package-lock.json", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 527, + "startColumn": 1, + "startLine": 515 + } } } - } - ], - "message": { - "text": "Package: cross-spawn\nInstalled Version: 7.0.3\nVulnerability CVE-2024-21538\nSeverity: HIGH\nFixed Version: 7.0.5, 6.0.6\nLink: [CVE-2024-21538](https://avd.aquasec.com/nvd/cve-2024-21538)" + ], + "message": { + "text": "Package: cross-spawn\nInstalled Version: 7.0.3\nVulnerability CVE-2024-21538\nSeverity: HIGH\nFixed Version: 7.0.5, 6.0.6\nLink: [CVE-2024-21538](https://avd.aquasec.com/nvd/cve-2024-21538)" + }, + "ruleId": "CVE-2024-21538", + "ruleIndex": 2 }, - "ruleId": "CVE-2024-21538", - "ruleIndex": 1 - }, - { - "level": "warning", - "locations": [ - { - "message": { - "text": "requirements.txt: django@1.11.29" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "requirements.txt", - "uriBaseId": "ROOTPATH" + { + "level": "warning", + "locations": [ + { + "message": { + "text": "package-lock.json: js-yaml@4.1.0" }, - "region": { - "endColumn": 1, - "endLine": 1, - "startColumn": 1, - "startLine": 1 + "physicalLocation": { + "artifactLocation": { + "uri": "package-lock.json", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1003, + "startColumn": 1, + "startLine": 993 + } } } - } - ], - "message": { - "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2024-45231\nSeverity: MEDIUM\nFixed Version: 5.1.1, 5.0.9, 4.2.16\nLink: [CVE-2024-45231](https://avd.aquasec.com/nvd/cve-2024-45231)" + ], + "message": { + "text": "Package: js-yaml\nInstalled Version: 4.1.0\nVulnerability CVE-2025-64718\nSeverity: MEDIUM\nFixed Version: 4.1.1, 3.14.2\nLink: [CVE-2025-64718](https://avd.aquasec.com/nvd/cve-2025-64718)" + }, + "ruleId": "CVE-2025-64718", + "ruleIndex": 3 }, - "ruleId": "CVE-2024-45231", - "ruleIndex": 9 - }, - { - "level": "warning", - "locations": [ - { - "message": { - "text": "requirements.txt: django@1.11.29" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "requirements.txt", - "uriBaseId": "ROOTPATH" + { + "level": "error", + "locations": [ + { + "message": { + "text": "package-lock.json: minimatch@3.1.2" }, - "region": { - "endColumn": 1, - "endLine": 1, - "startColumn": 1, - "startLine": 1 + "physicalLocation": { + "artifactLocation": { + "uri": "package-lock.json", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1101, + "startColumn": 1, + "startLine": 1091 + } } } - } - ], - "message": { - "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2025-48432\nSeverity: MEDIUM\nFixed Version: 5.2.2, 5.1.10, 4.2.22\nLink: [CVE-2025-48432](https://avd.aquasec.com/nvd/cve-2025-48432)" + ], + "message": { + "text": "Package: minimatch\nInstalled Version: 3.1.2\nVulnerability CVE-2026-26996\nSeverity: HIGH\nFixed Version: 10.2.1, 9.0.6, 8.0.5, 7.4.7, 6.2.1, 5.1.7, 4.2.4, 3.1.3\nLink: [CVE-2026-26996](https://avd.aquasec.com/nvd/cve-2026-26996)" + }, + "ruleId": "CVE-2026-26996", + "ruleIndex": 4 }, - "ruleId": "CVE-2025-48432", - "ruleIndex": 10 - }, - { - "level": "warning", - "locations": [ - { - "message": { - "text": "package-lock.json: eslint@9.3.0" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "package-lock.json", - "uriBaseId": "ROOTPATH" + { + "level": "error", + "locations": [ + { + "message": { + "text": "package-lock.json: minimatch@3.1.2" }, - "region": { - "endColumn": 1, - "endLine": 633, - "startColumn": 1, - "startLine": 584 + "physicalLocation": { + "artifactLocation": { + "uri": "package-lock.json", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1101, + "startColumn": 1, + "startLine": 1091 + } } } - } - ], - "message": { - "text": "Package: eslint\nInstalled Version: 9.3.0\nVulnerability CVE-2025-50537\nSeverity: MEDIUM\nFixed Version: 9.26.0\nLink: [CVE-2025-50537](https://avd.aquasec.com/nvd/cve-2025-50537)" + ], + "message": { + "text": "Package: minimatch\nInstalled Version: 3.1.2\nVulnerability CVE-2026-27903\nSeverity: HIGH\nFixed Version: 10.2.3, 9.0.7, 8.0.6, 7.4.8, 6.2.2, 5.1.8, 4.2.5, 3.1.3\nLink: [CVE-2026-27903](https://avd.aquasec.com/nvd/cve-2026-27903)" + }, + "ruleId": "CVE-2026-27903", + "ruleIndex": 5 }, - "ruleId": "CVE-2025-50537", - "ruleIndex": 2 - }, - { - "level": "error", - "locations": [ - { - "message": { - "text": "requirements.txt: django@1.11.29" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "requirements.txt", - "uriBaseId": "ROOTPATH" + { + "level": "error", + "locations": [ + { + "message": { + "text": "package-lock.json: minimatch@3.1.2" }, - "region": { - "endColumn": 1, - "endLine": 1, - "startColumn": 1, - "startLine": 1 + "physicalLocation": { + "artifactLocation": { + "uri": "package-lock.json", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1101, + "startColumn": 1, + "startLine": 1091 + } } } - } - ], - "message": { - "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2025-57833\nSeverity: HIGH\nFixed Version: 4.2.24, 5.1.12, 5.2.6\nLink: [CVE-2025-57833](https://avd.aquasec.com/nvd/cve-2025-57833)" + ], + "message": { + "text": "Package: minimatch\nInstalled Version: 3.1.2\nVulnerability CVE-2026-27904\nSeverity: HIGH\nFixed Version: 10.2.3, 9.0.7, 8.0.6, 7.4.8, 6.2.2, 5.1.8, 4.2.5, 3.1.4\nLink: [CVE-2026-27904](https://avd.aquasec.com/nvd/cve-2026-27904)" + }, + "ruleId": "CVE-2026-27904", + "ruleIndex": 6 }, - "ruleId": "CVE-2025-57833", - "ruleIndex": 6 - }, - { - "level": "note", - "locations": [ - { - "message": { - "text": "package-lock.json: brace-expansion@1.1.11" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "package-lock.json", - "uriBaseId": "ROOTPATH" + { + "level": "error", + "locations": [ + { + "message": { + "text": "requirements.txt: django@1.11.29" }, - "region": { - "endColumn": 1, - "endLine": 357, - "startColumn": 1, - "startLine": 349 + "physicalLocation": { + "artifactLocation": { + "uri": "requirements.txt", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1, + "startColumn": 1, + "startLine": 1 + } } } - } - ], - "message": { - "text": "Package: brace-expansion\nInstalled Version: 1.1.11\nVulnerability CVE-2025-5889\nSeverity: LOW\nFixed Version: 2.0.2, 1.1.12, 3.0.1, 4.0.1\nLink: [CVE-2025-5889](https://avd.aquasec.com/nvd/cve-2025-5889)" + ], + "message": { + "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2025-64459\nSeverity: CRITICAL\nFixed Version: 5.2.8, 5.1.14, 4.2.26\nLink: [CVE-2025-64459](https://avd.aquasec.com/nvd/cve-2025-64459)" + }, + "ruleId": "CVE-2025-64459", + "ruleIndex": 7 }, - "ruleId": "CVE-2025-5889", - "ruleIndex": 0 - }, - { - "level": "error", - "locations": [ - { - "message": { - "text": "requirements.txt: django@1.11.29" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "requirements.txt", - "uriBaseId": "ROOTPATH" + { + "level": "error", + "locations": [ + { + "message": { + "text": "requirements.txt: django@1.11.29" }, - "region": { - "endColumn": 1, - "endLine": 1, - "startColumn": 1, - "startLine": 1 + "physicalLocation": { + "artifactLocation": { + "uri": "requirements.txt", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1, + "startColumn": 1, + "startLine": 1 + } } } - } - ], - "message": { - "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2025-64458\nSeverity: HIGH\nFixed Version: 5.2.8, 5.1.14, 4.2.26\nLink: [CVE-2025-64458](https://avd.aquasec.com/nvd/cve-2025-64458)" + ], + "message": { + "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2022-36359\nSeverity: HIGH\nFixed Version: 3.2.15, 4.0.7\nLink: [CVE-2022-36359](https://avd.aquasec.com/nvd/cve-2022-36359)" + }, + "ruleId": "CVE-2022-36359", + "ruleIndex": 8 }, - "ruleId": "CVE-2025-64458", - "ruleIndex": 7 - }, - { - "level": "error", - "locations": [ - { - "message": { - "text": "requirements.txt: django@1.11.29" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "requirements.txt", - "uriBaseId": "ROOTPATH" + { + "level": "error", + "locations": [ + { + "message": { + "text": "requirements.txt: django@1.11.29" }, - "region": { - "endColumn": 1, - "endLine": 1, - "startColumn": 1, - "startLine": 1 + "physicalLocation": { + "artifactLocation": { + "uri": "requirements.txt", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1, + "startColumn": 1, + "startLine": 1 + } } } - } - ], - "message": { - "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2025-64459\nSeverity: CRITICAL\nFixed Version: 5.2.8, 5.1.14, 4.2.26\nLink: [CVE-2025-64459](https://avd.aquasec.com/nvd/cve-2025-64459)" + ], + "message": { + "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2025-57833\nSeverity: HIGH\nFixed Version: 4.2.24, 5.1.12, 5.2.6\nLink: [CVE-2025-57833](https://avd.aquasec.com/nvd/cve-2025-57833)" + }, + "ruleId": "CVE-2025-57833", + "ruleIndex": 9 }, - "ruleId": "CVE-2025-64459", - "ruleIndex": 4 - }, - { - "level": "warning", - "locations": [ - { - "message": { - "text": "package-lock.json: js-yaml@4.1.0" - }, - "physicalLocation": { - "artifactLocation": { - "uri": "package-lock.json", - "uriBaseId": "ROOTPATH" + { + "level": "error", + "locations": [ + { + "message": { + "text": "requirements.txt: django@1.11.29" }, - "region": { - "endColumn": 1, - "endLine": 1003, - "startColumn": 1, - "startLine": 993 + "physicalLocation": { + "artifactLocation": { + "uri": "requirements.txt", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1, + "startColumn": 1, + "startLine": 1 + } } } - } - ], - "message": { - "text": "Package: js-yaml\nInstalled Version: 4.1.0\nVulnerability CVE-2025-64718\nSeverity: MEDIUM\nFixed Version: 4.1.1, 3.14.2\nLink: [CVE-2025-64718](https://avd.aquasec.com/nvd/cve-2025-64718)" + ], + "message": { + "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2025-64458\nSeverity: HIGH\nFixed Version: 5.2.8, 5.1.14, 4.2.26\nLink: [CVE-2025-64458](https://avd.aquasec.com/nvd/cve-2025-64458)" + }, + "ruleId": "CVE-2025-64458", + "ruleIndex": 10 }, - "ruleId": "CVE-2025-64718", - "ruleIndex": 3 - } - ], - "tool": { - "driver": { - "fullName": "Trivy Vulnerability Scanner", - "informationUri": "https://github.com/aquasecurity/trivy", - "name": "Trivy", - "rules": null, - "version": "0.66.0" + { + "level": "warning", + "locations": [ + { + "message": { + "text": "requirements.txt: django@1.11.29" + }, + "physicalLocation": { + "artifactLocation": { + "uri": "requirements.txt", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1, + "startColumn": 1, + "startLine": 1 + } + } + } + ], + "message": { + "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2021-33203\nSeverity: MEDIUM\nFixed Version: 2.2.24, 3.1.12, 3.2.4\nLink: [CVE-2021-33203](https://avd.aquasec.com/nvd/cve-2021-33203)" + }, + "ruleId": "CVE-2021-33203", + "ruleIndex": 11 + }, + { + "level": "warning", + "locations": [ + { + "message": { + "text": "requirements.txt: django@1.11.29" + }, + "physicalLocation": { + "artifactLocation": { + "uri": "requirements.txt", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1, + "startColumn": 1, + "startLine": 1 + } + } + } + ], + "message": { + "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2024-45231\nSeverity: MEDIUM\nFixed Version: 5.1.1, 5.0.9, 4.2.16\nLink: [CVE-2024-45231](https://avd.aquasec.com/nvd/cve-2024-45231)" + }, + "ruleId": "CVE-2024-45231", + "ruleIndex": 12 + }, + { + "level": "warning", + "locations": [ + { + "message": { + "text": "requirements.txt: django@1.11.29" + }, + "physicalLocation": { + "artifactLocation": { + "uri": "requirements.txt", + "uriBaseId": "ROOTPATH" + }, + "region": { + "endColumn": 1, + "endLine": 1, + "startColumn": 1, + "startLine": 1 + } + } + } + ], + "message": { + "text": "Package: django\nInstalled Version: 1.11.29\nVulnerability CVE-2025-48432\nSeverity: MEDIUM\nFixed Version: 5.2.2, 5.1.10, 4.2.22\nLink: [CVE-2025-48432](https://avd.aquasec.com/nvd/cve-2025-48432)" + }, + "ruleId": "CVE-2025-48432", + "ruleIndex": 13 + } + ], + "tool": { + "driver": { + "fullName": "Trivy Vulnerability Scanner", + "informationUri": "https://github.com/aquasecurity/trivy", + "name": "Trivy", + "rules": null, + "version": "0.69.3" + } } } - } -], -"version": "2.1.0" + ], + "version": "2.1.0" } diff --git a/plugins/tools/trivy/test/src/.codacy/codacy.yaml b/plugins/tools/trivy/test/src/.codacy/codacy.yaml index f9dabc55..b47f29c7 100644 --- a/plugins/tools/trivy/test/src/.codacy/codacy.yaml +++ b/plugins/tools/trivy/test/src/.codacy/codacy.yaml @@ -1,3 +1,3 @@ -runtimes: +runtimes: null tools: - - trivy@0.66.0 \ No newline at end of file + - trivy@0.69.3 diff --git a/plugins/tools/trivy/test/src/.codacy/tools-configs/languages-config.yaml b/plugins/tools/trivy/test/src/.codacy/tools-configs/languages-config.yaml index 6e686c11..9d685b32 100644 --- a/plugins/tools/trivy/test/src/.codacy/tools-configs/languages-config.yaml +++ b/plugins/tools/trivy/test/src/.codacy/tools-configs/languages-config.yaml @@ -23,11 +23,11 @@ tools: languages: [Go] extensions: [.go] files: [] - - name: semgrep + - name: opengrep languages: [Apex, C, CPP, CSharp, Dockerfile, Go, Java, Javascript, Kotlin, PHP, PLSQL, Python, Ruby, Rust, SQL, Scala, Shell, Swift, Terraform, TypeScript, YAML] - extensions: [.bash, .c, .cc, .cls, .cpp, .cs, .cxx, .dockerfile, .fnc, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .jsx, .kt, .kts, .mjs, .opal, .pck, .php, .pkb, .pkh, .pks, .plb, .pld, .plh, .pls, .podspec, .prc, .py, .rake, .rb, .rlib, .rs, .scala, .sh, .sql, .swift, .tf, .tpb, .tps, .trg, .trigger, .ts, .tsx, .tyb, .typ, .vue, .yaml, .yml] + extensions: [.bash, .c, .cc, .cls, .cpp, .cs, .cxx, .dockerfile, .env, .fnc, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .jsx, .kt, .kts, .mjs, .opal, .pck, .php, .pkb, .pkh, .pks, .plb, .pld, .plh, .pls, .podspec, .prc, .py, .rake, .rb, .rlib, .rs, .scala, .sh, .sql, .swift, .tf, .tpb, .tps, .trg, .trigger, .ts, .tsx, .tyb, .typ, .vue, .yaml, .yml] files: [] - name: trivy languages: [C, CPP, CSharp, Dart, Dockerfile, Elixir, Go, JSON, Java, Javascript, PHP, Python, Ruby, Rust, Scala, Swift, Terraform, TypeScript, XML, YAML] - extensions: [.c, .cc, .cpp, .cs, .cxx, .dart, .dockerfile, .ex, .exs, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .json, .jsx, .mjs, .opal, .php, .podspec, .pom, .py, .rake, .rb, .rlib, .rs, .scala, .swift, .tf, .ts, .tsx, .vue, .wsdl, .xml, .xsl, .yaml, .yml] - files: [.deps.json, Berksfile, Capfile, Cargo.lock, Cheffile, Directory.Packages.props, Dockerfile, Fastfile, Gemfile, Gemfile.lock, Guardfile, Package.resolved, Packages.props, Pipfile.lock, Podfile, Podfile.lock, Rakefile, Thorfile, Vagabondfile, Vagrantfile, build.sbt.lock, composer.lock, conan.lock, config.ru, go.mod, gradle.lockfile, mix.lock, package-lock.json, package.json, packages.config, packages.lock.json, pnpm-lock.yaml, poetry.lock, pom.xml, pubspec.lock, requirements.txt, uv.lock, yarn.lock] + extensions: [.c, .cc, .cpp, .cs, .cxx, .dart, .dockerfile, .env, .ex, .exs, .gemspec, .go, .h, .hpp, .ino, .java, .jbuilder, .js, .jsm, .json, .jsx, .mjs, .opal, .php, .podspec, .pom, .py, .rake, .rb, .rlib, .rs, .scala, .swift, .tf, .ts, .tsx, .vue, .wsdl, .xml, .xsl, .yaml, .yml] + files: [.deps.json, .env, .env.dev, .env.development, .env.prod, .env.production, .env.staging, Berksfile, Capfile, Cargo.lock, Cheffile, Directory.Packages.props, Dockerfile, Fastfile, Gemfile, Gemfile.lock, Guardfile, Package.resolved, Packages.props, Pipfile.lock, Podfile, Podfile.lock, Rakefile, Thorfile, Vagabondfile, Vagrantfile, build.sbt.lock, composer.lock, conan.lock, config.ru, go.mod, gradle.lockfile, mix.lock, package-lock.json, package.json, packages.config, packages.lock.json, pnpm-lock.yaml, poetry.lock, pom.xml, pubspec.lock, requirements.txt, uv.lock, yarn.lock] diff --git a/tools/semgrepConfigCreator.go b/tools/semgrepConfigCreator.go index 55229c06..e62983bd 100644 --- a/tools/semgrepConfigCreator.go +++ b/tools/semgrepConfigCreator.go @@ -2,22 +2,22 @@ package tools import ( "codacy/cli-v2/domain" - "codacy/cli-v2/plugins/tools/semgrep/embedded" + "codacy/cli-v2/plugins/tools/opengrep/embedded" "fmt" "strings" "gopkg.in/yaml.v3" ) -// semgrepRulesFile represents the structure of the rules.yaml file -type semgrepRulesFile struct { +// opengrepRulesFile represents the structure of the rules.yaml file +type opengrepRulesFile struct { Rules []map[string]interface{} `yaml:"rules"` } // FilterRulesFromFile extracts enabled rules from a rules.yaml file based on configuration func FilterRulesFromFile(rulesData []byte, config []domain.PatternConfiguration) ([]byte, error) { // Parse the YAML data - var allRules semgrepRulesFile + var allRules opengrepRulesFile if err := yaml.Unmarshal(rulesData, &allRules); err != nil { return nil, fmt.Errorf("failed to parse rules file: %w", err) } @@ -41,7 +41,7 @@ func FilterRulesFromFile(rulesData []byte, config []domain.PatternConfiguration) } // Filter the rules based on enabled patterns - var filteredRules semgrepRulesFile + var filteredRules opengrepRulesFile filteredRules.Rules = []map[string]interface{}{} for _, rule := range allRules.Rules { @@ -61,14 +61,13 @@ func FilterRulesFromFile(rulesData []byte, config []domain.PatternConfiguration) return yaml.Marshal(filteredRules) } -// GetSemgrepConfig gets the Semgrep configuration based on the pattern configuration. +// GetOpengrepConfig gets the Opengrep configuration based on the pattern configuration. // If no configuration is provided, returns all default rules. -func GetSemgrepConfig(config []domain.PatternConfiguration) ([]byte, error) { - return FilterRulesFromFile(embedded.GetSemgrepRules(), config) +func GetOpengrepConfig(config []domain.PatternConfiguration) ([]byte, error) { + return FilterRulesFromFile(embedded.GetOpengrepRules(), config) } -// GetDefaultSemgrepConfig gets the default Semgrep configuration -func GetDefaultSemgrepConfig() ([]byte, error) { - // Return the embedded rules - return embedded.GetSemgrepRules(), nil +// GetDefaultOpengrepConfig gets the default Opengrep configuration +func GetDefaultOpengrepConfig() ([]byte, error) { + return embedded.GetOpengrepRules(), nil } diff --git a/tools/semgrepConfigCreator_test.go b/tools/semgrepConfigCreator_test.go index d43ea033..35481b91 100644 --- a/tools/semgrepConfigCreator_test.go +++ b/tools/semgrepConfigCreator_test.go @@ -2,7 +2,7 @@ package tools import ( "codacy/cli-v2/domain" - "codacy/cli-v2/plugins/tools/semgrep/embedded" + "codacy/cli-v2/plugins/tools/opengrep/embedded" "testing" "github.com/stretchr/testify/assert" @@ -12,14 +12,14 @@ import ( // TestFilterRulesFromFile tests the FilterRulesFromFile function func TestFilterRulesFromFile(t *testing.T) { // Get the actual rules file content - rulesData := embedded.GetSemgrepRules() + rulesData := embedded.GetOpengrepRules() // Test case 1: Filter with enabled rules config := []domain.PatternConfiguration{ { Enabled: true, PatternDefinition: domain.PatternDefinition{ - Id: "Semgrep_ai.csharp.detect-openai.detect-openai", + Id: "Opengrep_ai.csharp.detect-openai.detect-openai", Enabled: true, }, }, @@ -29,7 +29,7 @@ func TestFilterRulesFromFile(t *testing.T) { assert.NoError(t, err) // Parse the result and verify we got filtered rules - var parsedRules semgrepRulesFile + var parsedRules opengrepRulesFile err = yaml.Unmarshal(result, &parsedRules) assert.NoError(t, err) assert.Equal(t, 1, len(parsedRules.Rules)) @@ -39,7 +39,7 @@ func TestFilterRulesFromFile(t *testing.T) { { Enabled: false, PatternDefinition: domain.PatternDefinition{ - Id: "Semgrep_nonexistent", + Id: "Opengrep_nonexistent", Enabled: false, }, }, @@ -55,42 +55,42 @@ func TestFilterRulesFromFile(t *testing.T) { assert.Contains(t, err.Error(), "failed to parse rules file") } -// TestGetSemgrepConfig tests the GetSemgrepConfig function -func TestGetSemgrepConfig(t *testing.T) { +// TestGetOpengrepConfig tests the GetOpengrepConfig function +func TestGetOpengrepConfig(t *testing.T) { // Test with valid configuration config := []domain.PatternConfiguration{ { Enabled: true, PatternDefinition: domain.PatternDefinition{ - Id: "Semgrep_ai.csharp.detect-openai.detect-openai", + Id: "Opengrep_ai.csharp.detect-openai.detect-openai", Enabled: true, }, }, } - result, err := GetSemgrepConfig(config) + result, err := GetOpengrepConfig(config) assert.NoError(t, err) - var parsedRules semgrepRulesFile + var parsedRules opengrepRulesFile err = yaml.Unmarshal(result, &parsedRules) assert.NoError(t, err) assert.Equal(t, 1, len(parsedRules.Rules)) // Test with empty configuration (should return all rules) - result, err = GetSemgrepConfig([]domain.PatternConfiguration{}) + result, err = GetOpengrepConfig([]domain.PatternConfiguration{}) assert.NoError(t, err) err = yaml.Unmarshal(result, &parsedRules) assert.NoError(t, err) assert.True(t, len(parsedRules.Rules) > 0) } -// TestGetDefaultSemgrepConfig tests the GetDefaultSemgrepConfig function -func TestGetDefaultSemgrepConfig(t *testing.T) { +// TestGetDefaultOpengrepConfig tests the GetDefaultOpengrepConfig function +func TestGetDefaultOpengrepConfig(t *testing.T) { // Test getting default config - result, err := GetDefaultSemgrepConfig() + result, err := GetDefaultOpengrepConfig() assert.NoError(t, err) - var parsedRules semgrepRulesFile + var parsedRules opengrepRulesFile err = yaml.Unmarshal(result, &parsedRules) assert.NoError(t, err) assert.True(t, len(parsedRules.Rules) > 0) diff --git a/tools/semgrepRunner.go b/tools/semgrepRunner.go index 955cd184..9790edc8 100644 --- a/tools/semgrepRunner.go +++ b/tools/semgrepRunner.go @@ -8,12 +8,10 @@ import ( "path/filepath" ) -// RunSemgrep executes Semgrep analysis on the specified directory -func RunSemgrep(workDirectory string, binary string, files []string, outputFile string, outputFormat string) error { - // Construct base command with -m semgrep to run semgrep module +// RunOpengrep executes Opengrep analysis on the specified directory +func RunOpengrep(workDirectory string, binary string, files []string, outputFile string, outputFormat string) error { cmdArgs := []string{"scan"} - // Defaults from https://github.com/codacy/codacy-semgrep/blob/master/internal/tool/command.go cmdArgs = append(cmdArgs, "--max-memory", "2560") cmdArgs = append(cmdArgs, "--timeout", "5") cmdArgs = append(cmdArgs, "--timeout-threshold", "3") @@ -25,11 +23,11 @@ func RunSemgrep(workDirectory string, binary string, files []string, outputFile cmdArgs = append(cmdArgs, "--sarif") } - // Define possible Semgrep config file names - semgrepConfigFiles := []string{"semgrep.yml", "semgrep.yaml", "semgrep/semgrep.yml"} + // Define possible Opengrep config file names (uses semgrep-compatible config format) + opengrepConfigFiles := []string{"semgrep.yml", "semgrep.yaml", "semgrep/semgrep.yml"} // Check if a config file exists in the expected location and use it if present - if configFile, exists := ConfigFileExists(config.Config, semgrepConfigFiles...); exists { + if configFile, exists := ConfigFileExists(config.Config, opengrepConfigFiles...); exists { cmdArgs = append(cmdArgs, "--config", configFile) } else { // add --config auto only if no config file exists @@ -43,7 +41,7 @@ func RunSemgrep(workDirectory string, binary string, files []string, outputFile cmdArgs = append(cmdArgs, ".") } - // Create Semgrep command + // Create Opengrep command cmd := exec.Command(binary, cmdArgs...) cmd.Dir = workDirectory @@ -62,11 +60,11 @@ func RunSemgrep(workDirectory string, binary string, files []string, outputFile } cmd.Stderr = os.Stderr - // Run Semgrep + // Run Opengrep if err := cmd.Run(); err != nil { - // Semgrep returns non-zero exit code when it finds issues, which is expected + // Opengrep returns non-zero exit code when it finds issues, which is expected if _, ok := err.(*exec.ExitError); !ok { - return fmt.Errorf("failed to run semgrep: %w", err) + return fmt.Errorf("failed to run opengrep: %w", err) } } diff --git a/tools/testdata/repositories/trivy/expected.sarif b/tools/testdata/repositories/trivy/expected.sarif index 3c4b75be..77bc1d99 100644 --- a/tools/testdata/repositories/trivy/expected.sarif +++ b/tools/testdata/repositories/trivy/expected.sarif @@ -37,7 +37,7 @@ } } ], - "version": "0.66.0" + "version": "0.69.3" } }, "results": [