@codacy/tools-opengrep-1 0.23.1 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -10
- package/dist/index.js +143 -44
- package/dist/metadata.js +110 -8
- package/package.json +2 -2
- package/src/rules.yaml +26764 -13237
package/README.md
CHANGED
|
@@ -24,20 +24,47 @@ Multi-language SAST (Static Application Security Testing) scanner using the [Ope
|
|
|
24
24
|
| Strategy | CLI |
|
|
25
25
|
| Languages | 30+ (Python, JavaScript, TypeScript, Java, Go, Ruby, C, C++, etc.) |
|
|
26
26
|
| Binary | `opengrep` |
|
|
27
|
-
| File patterns |
|
|
27
|
+
| File patterns | ~70 extensions derived from the languages above, plus `Dockerfile` |
|
|
28
28
|
| Pattern count | ~2500 |
|
|
29
29
|
| Extra dependency | `yaml` (for YAML rule config parsing/generation) |
|
|
30
30
|
|
|
31
31
|
## Rule bundling
|
|
32
32
|
|
|
33
|
-
Opengrep uses YAML rule files for detection. The adapter bundles ~
|
|
33
|
+
Opengrep uses YAML rule files for detection. The adapter bundles ~2500 rules into `src/rules.yaml`, sourced from:
|
|
34
34
|
|
|
35
|
-
1. **
|
|
36
|
-
2. **GitLab SAST rules** — MIT-licensed
|
|
37
|
-
3. **Codacy custom rules** —
|
|
35
|
+
1. **opengrep/opengrep-rules** — the registry rules, pinned at the same commit as the Codacy image
|
|
36
|
+
2. **GitLab SAST rules** — MIT-licensed, from `gitlab.com/gitlab-org/security-products/sast-rules`
|
|
37
|
+
3. **Codacy custom rules** — `docs/codacy-rules*.yaml` in `codacy/codacy-opengrep`
|
|
38
38
|
|
|
39
39
|
The bundled `src/rules.yaml` is **committed to the repository** for consistency and reproducibility.
|
|
40
40
|
|
|
41
|
+
### Keeping it in step with the Codacy image
|
|
42
|
+
|
|
43
|
+
All three sources, their pinned commits and their file filters are mirrored from
|
|
44
|
+
`codacy/codacy-opengrep`'s `internal/docgen/parsing.go`. Keep them that way: the image is the
|
|
45
|
+
reference implementation, and `scripts/fetch-rules.mjs` says which upstream function each piece
|
|
46
|
+
came from.
|
|
47
|
+
|
|
48
|
+
Three mistakes in that mirroring cost **296 of 2534 patterns (12%)**, every one of them silent —
|
|
49
|
+
the pattern stays in `patterns.json`, `init --auto` enables it, the config claims it is active, and
|
|
50
|
+
it simply never fires:
|
|
51
|
+
|
|
52
|
+
- **Rule ids were derived from the file path.** GitLab ids are written in the file and must be
|
|
53
|
+
taken verbatim. Path derivation looks right for the top-level tree (`java/crypto/rule-X.yml`
|
|
54
|
+
really does hold `java_crypto_rule-X`) and is wrong for the licence-tiered one, where
|
|
55
|
+
`rules/lgpl-cc/properties/spring/accesscontrol/rule-Y.yml` holds `properties_spring_rule-Y`. The
|
|
56
|
+
sharpest case is `rule-JwtDecodeWithoutVerify.yml`, whose id uses an underscore where the
|
|
57
|
+
filename uses a hyphen. 265 of 588 GitLab rules were lost this way.
|
|
58
|
+
- **The registry source was upstream `semgrep/semgrep-rules`**, not Opengrep's fork. The two share
|
|
59
|
+
most ids, so the output looks plausible while individual rules go missing.
|
|
60
|
+
- **YAML was read and rewritten line by line.** That corrupted multi-line flow scalars — the
|
|
61
|
+
generated file stopped parsing, and opengrep then reported _zero findings for the entire run_
|
|
62
|
+
rather than an error — and it skipped every `tests/` directory, where some shipped rules live.
|
|
63
|
+
|
|
64
|
+
`test/rules-coverage.test.ts` is the guard: it fails if any catalogued pattern has no rule, and if
|
|
65
|
+
the generated file does not parse. Run `pnpm fetch-rules` when it does; the script prints the
|
|
66
|
+
orphaned ids.
|
|
67
|
+
|
|
41
68
|
## Updating patterns
|
|
42
69
|
|
|
43
70
|
```bash
|
|
@@ -57,7 +84,8 @@ Pattern IDs follow the format `Semgrep_python.lang.security.audit.exec-detected.
|
|
|
57
84
|
pnpm fetch-rules
|
|
58
85
|
|
|
59
86
|
# This clones the rule repos, extracts matching rules, and writes src/rules.yaml
|
|
60
|
-
# Only rules whose IDs match src/patterns.json are included
|
|
87
|
+
# Only rules whose IDs match src/patterns.json are included — and the script now
|
|
88
|
+
# warns loudly about the reverse, a catalogued pattern with no rule to run.
|
|
61
89
|
|
|
62
90
|
# Commit the result
|
|
63
91
|
git add src/rules.yaml
|
|
@@ -99,8 +127,9 @@ codacy-analysis analyze . --tool opengrep --install-dependencies
|
|
|
99
127
|
```
|
|
100
128
|
|
|
101
129
|
`install()` downloads the matching statically-linked binary from GitHub releases
|
|
102
|
-
(no archive to unpack) and `chmod +x`es it
|
|
103
|
-
mapping mirrors opengrep's official `install.sh
|
|
130
|
+
(no archive to unpack) and `chmod +x`es it (not on Windows). The
|
|
131
|
+
platform/arch/libc → asset mapping mirrors opengrep's official `install.sh` and
|
|
132
|
+
`install.ps1`:
|
|
104
133
|
|
|
105
134
|
| Platform | Asset |
|
|
106
135
|
| ------------------------- | ---------------------------- |
|
|
@@ -110,11 +139,15 @@ mapping mirrors opengrep's official `install.sh`:
|
|
|
110
139
|
| Linux arm64 (glibc) | `opengrep_manylinux_aarch64` |
|
|
111
140
|
| Linux x64 (musl/Alpine) | `opengrep_musllinux_x86` |
|
|
112
141
|
| Linux arm64 (musl/Alpine) | `opengrep_musllinux_aarch64` |
|
|
142
|
+
| Windows x64 | `opengrep_windows_x86.exe` |
|
|
143
|
+
| Windows arm64 (emulated) | `opengrep_windows_x86.exe` |
|
|
113
144
|
|
|
114
145
|
To install manually instead:
|
|
115
146
|
|
|
116
147
|
```bash
|
|
117
148
|
curl -fsSL https://raw.githubusercontent.com/opengrep/opengrep/main/install.sh | bash
|
|
149
|
+
# Windows (PowerShell)
|
|
150
|
+
irm https://raw.githubusercontent.com/opengrep/opengrep/main/install.ps1 | iex
|
|
118
151
|
```
|
|
119
152
|
|
|
120
153
|
## Notes for maintainers
|
|
@@ -152,11 +185,11 @@ curl -fsSL https://raw.githubusercontent.com/opengrep/opengrep/main/install.sh |
|
|
|
152
185
|
|
|
153
186
|
- **Tool ID is `Semgrep`** for legacy compatibility with the Codacy platform. The `displayName` is set to `Opengrep` for CLI display. Never change the tool ID without coordinating with the Codacy platform team.
|
|
154
187
|
- **Config materialization**: When Codacy patterns are specified, the adapter loads `src/rules.yaml`, filters to enabled rules, and writes a filtered config to `.codacy/generated/opengrep-rules.yaml`.
|
|
155
|
-
- **check_id
|
|
188
|
+
- **check_id is the bare rule ID**: every invocation passes `--no-rewrite-rule-ids`. Without it Opengrep prefixes `check_id` with the config file's directory relative to cwd (`.codacy/generated/x.yaml` → `codacy.generated.`), and the adapter used to reproduce that path math to strip the prefix again — never verified on Windows, where a mismatch would silently drop every finding at the enabled-pattern check. With the flag the rule ID maps to a pattern ID directly on every OS.
|
|
156
189
|
- **Config file search**: `.semgrep.yaml`, `.opengrep.yaml`, `.semgrep.yml`, `.opengrep.yml` (in that order).
|
|
157
190
|
- **Opengrep errors**: Parse errors (syntax errors, partial parsing) from Opengrep's JSON `errors` array are converted to structured `AnalysisError` objects with `filePath`. Stderr (scan status table) is logged at debug level only.
|
|
158
191
|
- **Rule ID format**: Semgrep-rules use `{dir}.{filename}.{ruleId}` (dots), GitLab rules use `{dir}_{filename}` (underscores), Codacy custom rules keep their original IDs.
|
|
159
|
-
- **Install / binary download**: `install()` downloads the bare per-platform binary from `https://github.com/opengrep/opengrep/releases/download/v{version}/{asset}` and `chmod +x`es it into `~/.codacy/tools/`. The release tag carries a `v` prefix (`v1.26.0`) even though `preferredVersion` does not. On Linux the libc flavour is detected with an `ldd /bin/sh` probe (`musl` → musllinux, else manylinux); detection failures fall back to glibc/manylinux. Unlike install.sh, the Codacy-managed install does **not** verify the cosign `.cert`/`.sig` signatures — if signature verification becomes a requirement, fetch those sibling assets and validate before chmod.
|
|
192
|
+
- **Install / binary download**: `install()` downloads the bare per-platform binary from `https://github.com/opengrep/opengrep/releases/download/v{version}/{asset}` and `chmod +x`es it into `~/.codacy/tools/`. The release tag carries a `v` prefix (`v1.26.0`) even though `preferredVersion` does not. On Linux the libc flavour is detected with an `ldd /bin/sh` probe (`musl` → musllinux, else manylinux); detection failures fall back to glibc/manylinux. On Windows the binary is saved as `opengrep.exe`; upstream builds only x64, which `install.ps1` also installs on ARM64 (emulated), so we do the same. **From opengrep 2.0.0 the Windows asset becomes `opengrep_windows_x86.zip`** (exe + DLLs) — bumping `preferredVersion` past 2.0 needs an extraction step. The argv chunk budget drops to `MAX_ARGV_BYTES` (30,000) on Windows, whose command line is capped at 32,767 characters. Unlike install.sh, the Codacy-managed install does **not** verify the cosign `.cert`/`.sig` signatures — if signature verification becomes a requirement, fetch those sibling assets and validate before chmod.
|
|
160
193
|
- **Argv-size chunking (no directory walk)**: The adapter always passes Opengrep an **explicit file list** — the runner's already git-ignored, exclude-filtered target set — so Opengrep never walks the repository tree itself. `chunkFilesByArgvBudget()` splits that list into the **fewest, largest** chunks that each fit `ARGV_BYTE_BUDGET` (200 KB, well under `ARG_MAX`), and each chunk is scanned in its own `opengrep scan` invocation; findings and errors are merged across chunks. Chunk by **size, not count**: every invocation re-compiles `rules.yaml`, so fewer/larger chunks amortize that fixed cost. The earlier directory/“root” fallback was removed because on huge repos (a single tracked file at the repo root collapsed the minimal-cover dirs to `.`) it made Opengrep walk the entire tree — re-scanning excluded/generated/vendored files and timing out at the runner's 10-minute limit.
|
|
161
194
|
- **File-size cap**: invocations pass `--max-target-bytes 1000000` (~1 MB). This restores Opengrep's default size cap — the adapter previously passed `0`, which **disables** the cap, so giant generated/minified bundles were scanned and dominated runtime. The cap applies to explicitly-listed files (verified on v1.16.4). Note: `--exclude-minified-files` is **not** used — that flag is rejected by the bundled binary unless `--experimental` (a different engine) is also passed, so we rely on the size cap instead. (The runner also enforces a tighter 150 KB per-file limit centrally before files reach the adapter, so this `--max-target-bytes` is now a secondary defense.)
|
|
162
195
|
- **Partial results on timeout**: the per-chunk loop checks `ctx.signal` (the runner's timeout abort) between chunks and passes it to `spawnTool`, so an in-flight scan is killed promptly. On abort the adapter keeps the findings from completed chunks and adds a single `Timeout` error (→ `status: "partial"`) rather than losing everything. This is why chunking matters beyond ARG_MAX: it's the granularity at which a long scan can be stopped with results preserved.
|
package/dist/index.js
CHANGED
|
@@ -30722,14 +30722,18 @@ var pattern_mappings_default = {
|
|
|
30722
30722
|
// src/metadata.ts
|
|
30723
30723
|
var descriptor = {
|
|
30724
30724
|
id: "Semgrep",
|
|
30725
|
+
shortName: "opengrep",
|
|
30725
30726
|
displayName: "Opengrep",
|
|
30726
30727
|
preferredVersion: "1.26.0",
|
|
30728
|
+
// Canonical `KNOWN_LANGUAGES` names, which is what `init --auto` matches against
|
|
30729
|
+
// (`init.ts:882`). The engine's own names differ and must be translated here:
|
|
30730
|
+
// Bash/Shell and Vue/Javascript collapse onto one entry each, since `.sh` and
|
|
30731
|
+
// `.vue` are already those languages. Guarded by `descriptor-languages.test.ts`.
|
|
30727
30732
|
languages: [
|
|
30728
30733
|
"Apex",
|
|
30729
|
-
"Bash",
|
|
30730
30734
|
"C",
|
|
30731
|
-
"
|
|
30732
|
-
"
|
|
30735
|
+
"CPP",
|
|
30736
|
+
"CSharp",
|
|
30733
30737
|
"Clojure",
|
|
30734
30738
|
"Dart",
|
|
30735
30739
|
"Dockerfile",
|
|
@@ -30737,7 +30741,7 @@ var descriptor = {
|
|
|
30737
30741
|
"Go",
|
|
30738
30742
|
"HTML",
|
|
30739
30743
|
"Java",
|
|
30740
|
-
"
|
|
30744
|
+
"Javascript",
|
|
30741
30745
|
"JSON",
|
|
30742
30746
|
"Kotlin",
|
|
30743
30747
|
"Lua",
|
|
@@ -30750,13 +30754,111 @@ var descriptor = {
|
|
|
30750
30754
|
"Swift",
|
|
30751
30755
|
"Terraform",
|
|
30752
30756
|
"TypeScript",
|
|
30753
|
-
"
|
|
30754
|
-
"Vue",
|
|
30757
|
+
"VisualBasic",
|
|
30755
30758
|
"XML",
|
|
30756
30759
|
"YAML"
|
|
30757
30760
|
],
|
|
30758
|
-
|
|
30759
|
-
|
|
30761
|
+
// Derived from `languages` above, via `LANGUAGE_CONFIG`, plus the extensions
|
|
30762
|
+
// sibling adapters already route for those same languages (`.cjs`, `.hh`,
|
|
30763
|
+
// `.jsonc`, `.json5`, `.pyi`, `.dash`, `.ksh`) — `LANGUAGE_CONFIG` is a
|
|
30764
|
+
// detection map and does not claim to be exhaustive per tool.
|
|
30765
|
+
//
|
|
30766
|
+
// This was `["*"]`, which `routeFilesToTool` short-circuits to "every file", so
|
|
30767
|
+
// opengrep was handed the whole repository: on one 1774-file repo, 358 of them
|
|
30768
|
+
// (20%) were png/jpg/font assets. Opengrep resolves a language by extension and
|
|
30769
|
+
// skips what it cannot parse, so findings were never affected — but the paths
|
|
30770
|
+
// still cost a realpath+stat each, inflated the reported file count, and ate the
|
|
30771
|
+
// 200 KB argv budget, splitting one `opengrep scan` into two.
|
|
30772
|
+
//
|
|
30773
|
+
// Keep this a superset of `LANGUAGE_CONFIG`'s extensions for every declared
|
|
30774
|
+
// language; `opengrep-1/test/file-patterns.test.ts` fails if a language gains one
|
|
30775
|
+
// that is not routed here, because a missed extension is a silent coverage loss.
|
|
30776
|
+
filePatterns: [
|
|
30777
|
+
"**/*.bash",
|
|
30778
|
+
"**/*.c",
|
|
30779
|
+
"**/*.cc",
|
|
30780
|
+
"**/*.cjs",
|
|
30781
|
+
"**/*.clj",
|
|
30782
|
+
"**/*.cljc",
|
|
30783
|
+
"**/*.cljs",
|
|
30784
|
+
"**/*.cls",
|
|
30785
|
+
"**/*.cpp",
|
|
30786
|
+
"**/*.cs",
|
|
30787
|
+
"**/*.cxx",
|
|
30788
|
+
"**/*.dart",
|
|
30789
|
+
"**/*.dash",
|
|
30790
|
+
"**/*.dockerfile",
|
|
30791
|
+
"**/*.edn",
|
|
30792
|
+
"**/*.env",
|
|
30793
|
+
"**/*.ex",
|
|
30794
|
+
"**/*.exs",
|
|
30795
|
+
"**/*.gemspec",
|
|
30796
|
+
"**/*.go",
|
|
30797
|
+
"**/*.h",
|
|
30798
|
+
"**/*.hh",
|
|
30799
|
+
"**/*.hpp",
|
|
30800
|
+
"**/*.htm",
|
|
30801
|
+
"**/*.html",
|
|
30802
|
+
"**/*.ino",
|
|
30803
|
+
"**/*.java",
|
|
30804
|
+
"**/*.jbuilder",
|
|
30805
|
+
"**/*.js",
|
|
30806
|
+
"**/*.jsm",
|
|
30807
|
+
"**/*.json",
|
|
30808
|
+
"**/*.json5",
|
|
30809
|
+
"**/*.jsonc",
|
|
30810
|
+
"**/*.jsx",
|
|
30811
|
+
"**/*.ksh",
|
|
30812
|
+
"**/*.kt",
|
|
30813
|
+
"**/*.kts",
|
|
30814
|
+
"**/*.lua",
|
|
30815
|
+
"**/*.luau",
|
|
30816
|
+
"**/*.mjs",
|
|
30817
|
+
"**/*.opal",
|
|
30818
|
+
"**/*.php",
|
|
30819
|
+
"**/*.podspec",
|
|
30820
|
+
"**/*.pom",
|
|
30821
|
+
"**/*.py",
|
|
30822
|
+
"**/*.pyi",
|
|
30823
|
+
"**/*.rake",
|
|
30824
|
+
"**/*.rb",
|
|
30825
|
+
"**/*.rlib",
|
|
30826
|
+
"**/*.rs",
|
|
30827
|
+
"**/*.scala",
|
|
30828
|
+
"**/*.sh",
|
|
30829
|
+
"**/*.swift",
|
|
30830
|
+
"**/*.tf",
|
|
30831
|
+
"**/*.trigger",
|
|
30832
|
+
"**/*.ts",
|
|
30833
|
+
"**/*.tsx",
|
|
30834
|
+
"**/*.vb",
|
|
30835
|
+
"**/*.vue",
|
|
30836
|
+
"**/*.wsdl",
|
|
30837
|
+
"**/*.xhtml",
|
|
30838
|
+
"**/*.xml",
|
|
30839
|
+
"**/*.xsl",
|
|
30840
|
+
"**/*.yaml",
|
|
30841
|
+
"**/*.yml",
|
|
30842
|
+
// Source files with no extension. `LANGUAGE_CONFIG.files` is a *detection*
|
|
30843
|
+
// list — it is mostly lockfiles (`yarn.lock`, `go.sum`, `poetry.lock`), which
|
|
30844
|
+
// identify a language without being source in it — so only the entries
|
|
30845
|
+
// opengrep can actually parse are routed here: Dockerfiles, and Ruby's
|
|
30846
|
+
// extensionless DSL files.
|
|
30847
|
+
"**/Dockerfile",
|
|
30848
|
+
"**/Dockerfile.*",
|
|
30849
|
+
"**/Berksfile",
|
|
30850
|
+
"**/Capfile",
|
|
30851
|
+
"**/Cheffile",
|
|
30852
|
+
"**/Fastfile",
|
|
30853
|
+
"**/Gemfile",
|
|
30854
|
+
"**/Guardfile",
|
|
30855
|
+
"**/Podfile",
|
|
30856
|
+
"**/Rakefile",
|
|
30857
|
+
"**/Thorfile",
|
|
30858
|
+
"**/Vagrantfile",
|
|
30859
|
+
"**/config.ru"
|
|
30860
|
+
],
|
|
30861
|
+
supportedOS: ["linux", "darwin", "win32"],
|
|
30760
30862
|
supportedArch: ["x64", "arm64"],
|
|
30761
30863
|
supportedRunners: ["local", "container"],
|
|
30762
30864
|
frameworkMappings: pattern_mappings_default
|
|
@@ -30801,6 +30903,10 @@ function opengrepAssetName(osName, arch, muslLibc) {
|
|
|
30801
30903
|
if (arch === "arm64") return `opengrep_${flavour}_aarch64`;
|
|
30802
30904
|
return null;
|
|
30803
30905
|
}
|
|
30906
|
+
if (osName === "win32") {
|
|
30907
|
+
if (arch === "x64" || arch === "arm64") return "opengrep_windows_x86.exe";
|
|
30908
|
+
return null;
|
|
30909
|
+
}
|
|
30804
30910
|
return null;
|
|
30805
30911
|
}
|
|
30806
30912
|
async function isMuslLibc() {
|
|
@@ -30826,30 +30932,18 @@ async function getVersionFromBinary(binaryPath) {
|
|
|
30826
30932
|
}
|
|
30827
30933
|
}
|
|
30828
30934
|
async function resolveBinaryPath(ctx) {
|
|
30829
|
-
const codacyBin = import_path.default.join(ctx.toolInstallDir, BINARY);
|
|
30935
|
+
const codacyBin = import_path.default.join(ctx.toolInstallDir, (0, import_tooling.exeName)(BINARY));
|
|
30830
30936
|
const version = await getVersionFromBinary(codacyBin);
|
|
30831
30937
|
if (version) return codacyBin;
|
|
30832
30938
|
return BINARY;
|
|
30833
30939
|
}
|
|
30834
|
-
function
|
|
30835
|
-
const
|
|
30836
|
-
const
|
|
30837
|
-
if (
|
|
30838
|
-
|
|
30839
|
-
return components.filter(Boolean).join(".") + ".";
|
|
30840
|
-
}
|
|
30841
|
-
function stripCheckIdPrefix(checkId, configPrefix) {
|
|
30842
|
-
let stripped = checkId.startsWith("tmp.") ? checkId.slice(4) : checkId;
|
|
30843
|
-
if (configPrefix && stripped.startsWith(configPrefix)) {
|
|
30844
|
-
stripped = stripped.slice(configPrefix.length);
|
|
30845
|
-
}
|
|
30846
|
-
return stripped;
|
|
30847
|
-
}
|
|
30848
|
-
function truncate(str, maxLen) {
|
|
30849
|
-
if (str.length <= maxLen) return str;
|
|
30850
|
-
return str.slice(0, maxLen - 3) + "...";
|
|
30940
|
+
function firstSentence(message) {
|
|
30941
|
+
const oneLine = message.replace(/\n/g, " ");
|
|
30942
|
+
const match = /(^.*?[a-z]{2,}[.!?])\s+\W*[A-Z]/.exec(oneLine);
|
|
30943
|
+
if (match) return match[1];
|
|
30944
|
+
return oneLine.length > 500 ? oneLine.slice(0, 500) : oneLine;
|
|
30851
30945
|
}
|
|
30852
|
-
var ARGV_BYTE_BUDGET = 200 * 1024;
|
|
30946
|
+
var ARGV_BYTE_BUDGET = import_tooling.IS_WINDOWS ? import_tooling.MAX_ARGV_BYTES : 200 * 1024;
|
|
30853
30947
|
function chunkFilesByArgvBudget(files) {
|
|
30854
30948
|
const chunks = [];
|
|
30855
30949
|
let current = [];
|
|
@@ -30969,7 +31063,7 @@ var adapter = {
|
|
|
30969
31063
|
*/
|
|
30970
31064
|
async checkAvailability(ctx) {
|
|
30971
31065
|
ctx.logger.debug("Checking availability", { toolId: TOOL_ID });
|
|
30972
|
-
const codacyBin = import_path.default.join(ctx.toolInstallDir, BINARY);
|
|
31066
|
+
const codacyBin = import_path.default.join(ctx.toolInstallDir, (0, import_tooling.exeName)(BINARY));
|
|
30973
31067
|
const codacyVersion = await getVersionFromBinary(codacyBin);
|
|
30974
31068
|
if (codacyVersion) {
|
|
30975
31069
|
ctx.logger.debug("Found opengrep in codacy install dir", {
|
|
@@ -30999,21 +31093,22 @@ var adapter = {
|
|
|
30999
31093
|
return {
|
|
31000
31094
|
available: false,
|
|
31001
31095
|
reason: "opengrep binary not found in PATH or Codacy install directory",
|
|
31002
|
-
installHint: "codacy-analysis analyze . --install-dependencies # auto-install into ~/.codacy\
|
|
31096
|
+
installHint: "codacy-analysis analyze . --install-dependencies # auto-install into ~/.codacy\n" + (import_tooling.IS_WINDOWS ? "irm https://raw.githubusercontent.com/opengrep/opengrep/main/install.ps1 | iex # manual (PowerShell)" : "curl -fsSL https://raw.githubusercontent.com/opengrep/opengrep/main/install.sh | bash # manual")
|
|
31003
31097
|
};
|
|
31004
31098
|
},
|
|
31005
31099
|
/**
|
|
31006
31100
|
* Downloads the opengrep binary from GitHub releases into `ctx.toolInstallDir`.
|
|
31007
31101
|
*
|
|
31008
31102
|
* Opengrep distributes a single statically-linked executable per platform
|
|
31009
|
-
* (no archive), so install is just a download + `chmod +x
|
|
31010
|
-
* platform/arch/libc → asset mapping mirrors opengrep's
|
|
31011
|
-
* (see {@link opengrepAssetName}). The
|
|
31012
|
-
* `ctx.toolInstallDir/opengrep
|
|
31013
|
-
*
|
|
31103
|
+
* (no archive), so install is just a download + `chmod +x` (no chmod on
|
|
31104
|
+
* Windows). The platform/arch/libc → asset mapping mirrors opengrep's
|
|
31105
|
+
* official install.sh / install.ps1 (see {@link opengrepAssetName}). The
|
|
31106
|
+
* binary lands at `ctx.toolInstallDir/opengrep` (`opengrep.exe` on Windows),
|
|
31107
|
+
* which `checkAvailability` probes first — so the runner's post-install
|
|
31108
|
+
* re-check picks up the managed install.
|
|
31014
31109
|
*
|
|
31015
31110
|
* Returns an `UnsupportedPlatform` error for targets opengrep has no binary
|
|
31016
|
-
* for
|
|
31111
|
+
* for, and a `DownloadError` if the fetch fails.
|
|
31017
31112
|
*/
|
|
31018
31113
|
async install(ctx) {
|
|
31019
31114
|
ctx.logger.info("Starting install", { toolId: TOOL_ID });
|
|
@@ -31028,17 +31123,17 @@ var adapter = {
|
|
|
31028
31123
|
toolId: TOOL_ID,
|
|
31029
31124
|
phase: "toolInstall",
|
|
31030
31125
|
kind: "UnsupportedPlatform",
|
|
31031
|
-
message: `Unsupported platform: ${platformKey}. Opengrep provides binaries for darwin-x64, darwin-arm64, linux-x64, and
|
|
31126
|
+
message: `Unsupported platform: ${platformKey}. Opengrep provides binaries for darwin-x64, darwin-arm64, linux-x64, linux-arm64, and win32-x64 (also used on win32-arm64).`,
|
|
31032
31127
|
level: "error"
|
|
31033
31128
|
}
|
|
31034
31129
|
};
|
|
31035
31130
|
}
|
|
31036
31131
|
const url = `https://github.com/opengrep/opengrep/releases/download/v${version}/${assetName}`;
|
|
31037
|
-
const destPath = import_path.default.join(ctx.toolInstallDir, BINARY);
|
|
31132
|
+
const destPath = import_path.default.join(ctx.toolInstallDir, (0, import_tooling.exeName)(BINARY));
|
|
31038
31133
|
try {
|
|
31039
31134
|
ctx.logger.info(`Downloading Opengrep v${version} for ${platformKey}...`);
|
|
31040
31135
|
await (0, import_tooling.downloadFile)(url, destPath, ctx.logger);
|
|
31041
|
-
await import_promises.default.chmod(destPath, 493);
|
|
31136
|
+
if (!import_tooling.IS_WINDOWS) await import_promises.default.chmod(destPath, 493);
|
|
31042
31137
|
ctx.logger.info(`Installed opengrep v${version} to ${destPath}`);
|
|
31043
31138
|
return { success: true, installedPath: destPath, installedVersion: version };
|
|
31044
31139
|
} catch (err) {
|
|
@@ -31086,8 +31181,9 @@ var adapter = {
|
|
|
31086
31181
|
* the enabled rules and write a generated config.
|
|
31087
31182
|
* 3. If no patterns and no local config, use the full bundled rules.yaml.
|
|
31088
31183
|
*
|
|
31089
|
-
*
|
|
31090
|
-
*
|
|
31184
|
+
* Every invocation passes `--no-rewrite-rule-ids`, so `check_id` is the rule
|
|
31185
|
+
* ID exactly as written in the config and maps to a pattern ID directly (see
|
|
31186
|
+
* the note on `baseArgs`).
|
|
31091
31187
|
*
|
|
31092
31188
|
* Exit codes:
|
|
31093
31189
|
* - 0: success (findings may or may not exist)
|
|
@@ -31160,6 +31256,7 @@ var adapter = {
|
|
|
31160
31256
|
"--json",
|
|
31161
31257
|
"--config",
|
|
31162
31258
|
configFile,
|
|
31259
|
+
"--no-rewrite-rule-ids",
|
|
31163
31260
|
"--timeout",
|
|
31164
31261
|
"5",
|
|
31165
31262
|
"--timeout-threshold",
|
|
@@ -31220,12 +31317,14 @@ var adapter = {
|
|
|
31220
31317
|
kind: errorType,
|
|
31221
31318
|
message,
|
|
31222
31319
|
level,
|
|
31223
|
-
filePath
|
|
31320
|
+
filePath,
|
|
31321
|
+
// Opengrep only reports a path on errors that stopped it scanning
|
|
31322
|
+
// that file, so a path here means the file was not analysed.
|
|
31323
|
+
...filePath ? { fileNotAnalyzed: true } : {}
|
|
31224
31324
|
});
|
|
31225
31325
|
}
|
|
31226
31326
|
}
|
|
31227
31327
|
const enabledPatterns = new Set(codacyConfig.patterns.map((p) => p.patternId));
|
|
31228
|
-
const configPrefix = configFile ? computeConfigPrefix(configFile, ctx.repositoryRoot) : "";
|
|
31229
31328
|
const findingsByFile = /* @__PURE__ */ new Map();
|
|
31230
31329
|
for (const finding of allFindings) {
|
|
31231
31330
|
if (finding.extra.is_ignored) continue;
|
|
@@ -31243,7 +31342,7 @@ var adapter = {
|
|
|
31243
31342
|
const lines = await (0, import_tooling.readFileLines)(absoluteFilePath);
|
|
31244
31343
|
const relPath = import_path.default.relative(ctx.repositoryRoot, absoluteFilePath);
|
|
31245
31344
|
for (const finding of fileFindings) {
|
|
31246
|
-
const ruleId =
|
|
31345
|
+
const ruleId = finding.check_id;
|
|
31247
31346
|
const patternId = `${TOOL_ID}_${ruleId}`;
|
|
31248
31347
|
if (enabledPatterns.size > 0 && !enabledPatterns.has(patternId)) {
|
|
31249
31348
|
continue;
|
|
@@ -31257,7 +31356,7 @@ var adapter = {
|
|
|
31257
31356
|
column: finding.start.col,
|
|
31258
31357
|
endLine: finding.end.line,
|
|
31259
31358
|
endColumn: finding.end.col,
|
|
31260
|
-
message:
|
|
31359
|
+
message: firstSentence(finding.extra.message ?? ""),
|
|
31261
31360
|
lineContent: (0, import_tooling.getLineContent)(lines, finding.start.line),
|
|
31262
31361
|
multilineContent: (0, import_tooling.getMultilineContent)(lines, finding.start.line, finding.end.line),
|
|
31263
31362
|
category: meta.category,
|
package/dist/metadata.js
CHANGED
|
@@ -255,14 +255,18 @@ var pattern_mappings_default = {
|
|
|
255
255
|
// src/metadata.ts
|
|
256
256
|
var descriptor = {
|
|
257
257
|
id: "Semgrep",
|
|
258
|
+
shortName: "opengrep",
|
|
258
259
|
displayName: "Opengrep",
|
|
259
260
|
preferredVersion: "1.26.0",
|
|
261
|
+
// Canonical `KNOWN_LANGUAGES` names, which is what `init --auto` matches against
|
|
262
|
+
// (`init.ts:882`). The engine's own names differ and must be translated here:
|
|
263
|
+
// Bash/Shell and Vue/Javascript collapse onto one entry each, since `.sh` and
|
|
264
|
+
// `.vue` are already those languages. Guarded by `descriptor-languages.test.ts`.
|
|
260
265
|
languages: [
|
|
261
266
|
"Apex",
|
|
262
|
-
"Bash",
|
|
263
267
|
"C",
|
|
264
|
-
"
|
|
265
|
-
"
|
|
268
|
+
"CPP",
|
|
269
|
+
"CSharp",
|
|
266
270
|
"Clojure",
|
|
267
271
|
"Dart",
|
|
268
272
|
"Dockerfile",
|
|
@@ -270,7 +274,7 @@ var descriptor = {
|
|
|
270
274
|
"Go",
|
|
271
275
|
"HTML",
|
|
272
276
|
"Java",
|
|
273
|
-
"
|
|
277
|
+
"Javascript",
|
|
274
278
|
"JSON",
|
|
275
279
|
"Kotlin",
|
|
276
280
|
"Lua",
|
|
@@ -283,13 +287,111 @@ var descriptor = {
|
|
|
283
287
|
"Swift",
|
|
284
288
|
"Terraform",
|
|
285
289
|
"TypeScript",
|
|
286
|
-
"
|
|
287
|
-
"Vue",
|
|
290
|
+
"VisualBasic",
|
|
288
291
|
"XML",
|
|
289
292
|
"YAML"
|
|
290
293
|
],
|
|
291
|
-
|
|
292
|
-
|
|
294
|
+
// Derived from `languages` above, via `LANGUAGE_CONFIG`, plus the extensions
|
|
295
|
+
// sibling adapters already route for those same languages (`.cjs`, `.hh`,
|
|
296
|
+
// `.jsonc`, `.json5`, `.pyi`, `.dash`, `.ksh`) — `LANGUAGE_CONFIG` is a
|
|
297
|
+
// detection map and does not claim to be exhaustive per tool.
|
|
298
|
+
//
|
|
299
|
+
// This was `["*"]`, which `routeFilesToTool` short-circuits to "every file", so
|
|
300
|
+
// opengrep was handed the whole repository: on one 1774-file repo, 358 of them
|
|
301
|
+
// (20%) were png/jpg/font assets. Opengrep resolves a language by extension and
|
|
302
|
+
// skips what it cannot parse, so findings were never affected — but the paths
|
|
303
|
+
// still cost a realpath+stat each, inflated the reported file count, and ate the
|
|
304
|
+
// 200 KB argv budget, splitting one `opengrep scan` into two.
|
|
305
|
+
//
|
|
306
|
+
// Keep this a superset of `LANGUAGE_CONFIG`'s extensions for every declared
|
|
307
|
+
// language; `opengrep-1/test/file-patterns.test.ts` fails if a language gains one
|
|
308
|
+
// that is not routed here, because a missed extension is a silent coverage loss.
|
|
309
|
+
filePatterns: [
|
|
310
|
+
"**/*.bash",
|
|
311
|
+
"**/*.c",
|
|
312
|
+
"**/*.cc",
|
|
313
|
+
"**/*.cjs",
|
|
314
|
+
"**/*.clj",
|
|
315
|
+
"**/*.cljc",
|
|
316
|
+
"**/*.cljs",
|
|
317
|
+
"**/*.cls",
|
|
318
|
+
"**/*.cpp",
|
|
319
|
+
"**/*.cs",
|
|
320
|
+
"**/*.cxx",
|
|
321
|
+
"**/*.dart",
|
|
322
|
+
"**/*.dash",
|
|
323
|
+
"**/*.dockerfile",
|
|
324
|
+
"**/*.edn",
|
|
325
|
+
"**/*.env",
|
|
326
|
+
"**/*.ex",
|
|
327
|
+
"**/*.exs",
|
|
328
|
+
"**/*.gemspec",
|
|
329
|
+
"**/*.go",
|
|
330
|
+
"**/*.h",
|
|
331
|
+
"**/*.hh",
|
|
332
|
+
"**/*.hpp",
|
|
333
|
+
"**/*.htm",
|
|
334
|
+
"**/*.html",
|
|
335
|
+
"**/*.ino",
|
|
336
|
+
"**/*.java",
|
|
337
|
+
"**/*.jbuilder",
|
|
338
|
+
"**/*.js",
|
|
339
|
+
"**/*.jsm",
|
|
340
|
+
"**/*.json",
|
|
341
|
+
"**/*.json5",
|
|
342
|
+
"**/*.jsonc",
|
|
343
|
+
"**/*.jsx",
|
|
344
|
+
"**/*.ksh",
|
|
345
|
+
"**/*.kt",
|
|
346
|
+
"**/*.kts",
|
|
347
|
+
"**/*.lua",
|
|
348
|
+
"**/*.luau",
|
|
349
|
+
"**/*.mjs",
|
|
350
|
+
"**/*.opal",
|
|
351
|
+
"**/*.php",
|
|
352
|
+
"**/*.podspec",
|
|
353
|
+
"**/*.pom",
|
|
354
|
+
"**/*.py",
|
|
355
|
+
"**/*.pyi",
|
|
356
|
+
"**/*.rake",
|
|
357
|
+
"**/*.rb",
|
|
358
|
+
"**/*.rlib",
|
|
359
|
+
"**/*.rs",
|
|
360
|
+
"**/*.scala",
|
|
361
|
+
"**/*.sh",
|
|
362
|
+
"**/*.swift",
|
|
363
|
+
"**/*.tf",
|
|
364
|
+
"**/*.trigger",
|
|
365
|
+
"**/*.ts",
|
|
366
|
+
"**/*.tsx",
|
|
367
|
+
"**/*.vb",
|
|
368
|
+
"**/*.vue",
|
|
369
|
+
"**/*.wsdl",
|
|
370
|
+
"**/*.xhtml",
|
|
371
|
+
"**/*.xml",
|
|
372
|
+
"**/*.xsl",
|
|
373
|
+
"**/*.yaml",
|
|
374
|
+
"**/*.yml",
|
|
375
|
+
// Source files with no extension. `LANGUAGE_CONFIG.files` is a *detection*
|
|
376
|
+
// list — it is mostly lockfiles (`yarn.lock`, `go.sum`, `poetry.lock`), which
|
|
377
|
+
// identify a language without being source in it — so only the entries
|
|
378
|
+
// opengrep can actually parse are routed here: Dockerfiles, and Ruby's
|
|
379
|
+
// extensionless DSL files.
|
|
380
|
+
"**/Dockerfile",
|
|
381
|
+
"**/Dockerfile.*",
|
|
382
|
+
"**/Berksfile",
|
|
383
|
+
"**/Capfile",
|
|
384
|
+
"**/Cheffile",
|
|
385
|
+
"**/Fastfile",
|
|
386
|
+
"**/Gemfile",
|
|
387
|
+
"**/Guardfile",
|
|
388
|
+
"**/Podfile",
|
|
389
|
+
"**/Rakefile",
|
|
390
|
+
"**/Thorfile",
|
|
391
|
+
"**/Vagrantfile",
|
|
392
|
+
"**/config.ru"
|
|
393
|
+
],
|
|
394
|
+
supportedOS: ["linux", "darwin", "win32"],
|
|
293
395
|
supportedArch: ["x64", "arm64"],
|
|
294
396
|
supportedRunners: ["local", "container"],
|
|
295
397
|
frameworkMappings: pattern_mappings_default
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codacy/tools-opengrep-1",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Opengrep adapter — CLI-mode multi-language SAST scanner",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"yaml": "^2.6.0",
|
|
13
|
-
"@codacy/tooling": "0.
|
|
13
|
+
"@codacy/tooling": "0.25.0"
|
|
14
14
|
},
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"author": "Codacy <support@codacy.com> (https://www.codacy.com)",
|