@codacy/tools-opengrep-1 0.23.0 → 0.24.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 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 | `*` (auto-detects by language) |
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 ~2200 rules into `src/rules.yaml`, sourced from:
33
+ Opengrep uses YAML rule files for detection. The adapter bundles ~2500 rules into `src/rules.yaml`, sourced from:
34
34
 
35
- 1. **semgrep/semgrep-rules** — community rules (pinned at commit `4ccd3b9`)
36
- 2. **GitLab SAST rules** — MIT-licensed rules from `gitlab.com/gitlab-org/security-products/sast-rules`
37
- 3. **Codacy custom rules** — from `codacy/codacy-opengrep` wrapper repo
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
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
- "C++",
30732
- "C#",
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
- "JavaScript",
30744
+ "Javascript",
30741
30745
  "JSON",
30742
30746
  "Kotlin",
30743
30747
  "Lua",
@@ -30750,12 +30754,110 @@ var descriptor = {
30750
30754
  "Swift",
30751
30755
  "Terraform",
30752
30756
  "TypeScript",
30753
- "Visual Basic",
30754
- "Vue",
30757
+ "VisualBasic",
30755
30758
  "XML",
30756
30759
  "YAML"
30757
30760
  ],
30758
- filePatterns: ["*"],
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
+ ],
30759
30861
  supportedOS: ["linux", "darwin"],
30760
30862
  supportedArch: ["x64", "arm64"],
30761
30863
  supportedRunners: ["local", "container"],
@@ -30845,9 +30947,11 @@ function stripCheckIdPrefix(checkId, configPrefix) {
30845
30947
  }
30846
30948
  return stripped;
30847
30949
  }
30848
- function truncate(str, maxLen) {
30849
- if (str.length <= maxLen) return str;
30850
- return str.slice(0, maxLen - 3) + "...";
30950
+ function firstSentence(message) {
30951
+ const oneLine = message.replace(/\n/g, " ");
30952
+ const match = /(^.*?[a-z]{2,}[.!?])\s+\W*[A-Z]/.exec(oneLine);
30953
+ if (match) return match[1];
30954
+ return oneLine.length > 500 ? oneLine.slice(0, 500) : oneLine;
30851
30955
  }
30852
30956
  var ARGV_BYTE_BUDGET = 200 * 1024;
30853
30957
  function chunkFilesByArgvBudget(files) {
@@ -31220,7 +31324,10 @@ var adapter = {
31220
31324
  kind: errorType,
31221
31325
  message,
31222
31326
  level,
31223
- filePath
31327
+ filePath,
31328
+ // Opengrep only reports a path on errors that stopped it scanning
31329
+ // that file, so a path here means the file was not analysed.
31330
+ ...filePath ? { fileNotAnalyzed: true } : {}
31224
31331
  });
31225
31332
  }
31226
31333
  }
@@ -31257,7 +31364,7 @@ var adapter = {
31257
31364
  column: finding.start.col,
31258
31365
  endLine: finding.end.line,
31259
31366
  endColumn: finding.end.col,
31260
- message: truncate(finding.extra.message, 250),
31367
+ message: firstSentence(finding.extra.message ?? ""),
31261
31368
  lineContent: (0, import_tooling.getLineContent)(lines, finding.start.line),
31262
31369
  multilineContent: (0, import_tooling.getMultilineContent)(lines, finding.start.line, finding.end.line),
31263
31370
  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
- "C++",
265
- "C#",
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
- "JavaScript",
277
+ "Javascript",
274
278
  "JSON",
275
279
  "Kotlin",
276
280
  "Lua",
@@ -283,12 +287,110 @@ var descriptor = {
283
287
  "Swift",
284
288
  "Terraform",
285
289
  "TypeScript",
286
- "Visual Basic",
287
- "Vue",
290
+ "VisualBasic",
288
291
  "XML",
289
292
  "YAML"
290
293
  ],
291
- filePatterns: ["*"],
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
+ ],
292
394
  supportedOS: ["linux", "darwin"],
293
395
  supportedArch: ["x64", "arm64"],
294
396
  supportedRunners: ["local", "container"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/tools-opengrep-1",
3
- "version": "0.23.0",
3
+ "version": "0.24.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.23.0"
13
+ "@codacy/tooling": "0.24.0"
14
14
  },
15
15
  "license": "MIT",
16
16
  "author": "Codacy <support@codacy.com> (https://www.codacy.com)",