@codacy/tools-bandit-1 0.18.0 → 0.20.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
@@ -1,6 +1,7 @@
1
1
  # @codacy/tools-bandit-1
2
2
 
3
3
  ## Table of Contents
4
+
4
5
  - [Overview](#overview)
5
6
  - [Updating patterns](#updating-patterns)
6
7
  - [Updating the Bandit version](#updating-the-bandit-version)
@@ -13,14 +14,14 @@
13
14
 
14
15
  Python security linter using the [Bandit](https://bandit.readthedocs.io/) binary. Uses the CLI execution strategy -- spawns `bandit` from a managed Python venv via `spawnTool()` and parses its JSON output.
15
16
 
16
- | Property | Value |
17
- |----------|-------|
18
- | Tool ID | `Bandit` |
19
- | Codacy UUID | `89b6fc6a-9137-4cf3-8b9f-dcc3bedfa738` |
20
- | Strategy | CLI |
21
- | Languages | Python |
22
- | Binary | `bandit` (pip-installed in venv) |
23
- | File patterns | `**/*.py` |
17
+ | Property | Value |
18
+ | ------------- | -------------------------------------- |
19
+ | Tool ID | `Bandit` |
20
+ | Codacy UUID | `89b6fc6a-9137-4cf3-8b9f-dcc3bedfa738` |
21
+ | Strategy | CLI |
22
+ | Languages | Python |
23
+ | Binary | `bandit` (pip-installed in venv) |
24
+ | File patterns | `**/*.py` |
24
25
 
25
26
  ## Updating patterns
26
27
 
@@ -50,12 +51,32 @@ pnpm test # Run tests (requires bandit in PATH or venv)
50
51
  ```
51
52
 
52
53
  To install bandit locally for testing:
54
+
53
55
  ```bash
54
56
  pip install bandit==1.8.3
55
57
  ```
56
58
 
57
59
  ## Notes for maintainers
58
60
 
61
+ - **Preset mappings (`src/pattern-mappings.json`)**: 18 of the 78 checks are gated on a
62
+ detected PyPI dependency, because they only ever fire against one library's API. Ten were
63
+ default-on and now stay out of a repo that does not declare the library — `B201` (Flask),
64
+ `B701` (Jinja2), `B702` (Mako), `B601` (Paramiko), `B320`/`B410` (lxml), `B506` (PyYAML),
65
+ `B113`/`B501` (requests) and `B308` (Django). Eight were default-off and are now reachable
66
+ at all: `B610`/`B611`/`B703` (Django SQLi/XSS), `B507` (Paramiko host keys), `B508`/`B509`
67
+ (PySNMP), `B413`/`B414` (PyCrypto vs. PyCryptodome — separate projects, so separate
68
+ entities). Left universal on purpose: the stdlib checks (`B301`–`B307`, `B324`) and `B412`,
69
+ whose httpoxy CGI handler has no manifest to read.
70
+
71
+ Two of these need a second key, because gating gets its evidence from **direct**
72
+ declarations only:
73
+ - `B701` is claimed by `flask` as well as `jinja2`. Flask hard-depends on Jinja2
74
+ (`Flask` → `jinja2>=3.1.2`), so a real Flask app usually never lists Jinja2 itself, and
75
+ gating on `jinja2` alone dropped a High-severity autoescape check from most Flask repos.
76
+ - `B501` is claimed by `httpx` as well as `requests`. Bandit's own
77
+ `crypto_request_no_cert_validation` plugin inspects both libraries, so an httpx-only repo
78
+ would otherwise lose the `verify=False` check.
79
+
59
80
  - Bandit requires Python 3 as a runtime. The adapter uses an isolated venv at `~/.codacy/runtimes/bandit-1/venv/`.
60
81
  - Exit code 0 = no findings, 1 = findings found (normal), >1 = error.
61
82
  - `col_offset` in bandit output is 0-based; the adapter adds 1 for the 1-based Issue model.
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ var patterns_default = [
47
47
  category: "Security",
48
48
  severityLevel: "High",
49
49
  title: "Avoid Use of Assert Statements",
50
- enabled: false,
50
+ enabled: true,
51
51
  languages: ["Python"],
52
52
  parameters: []
53
53
  },
@@ -92,7 +92,7 @@ var patterns_default = [
92
92
  category: "Security",
93
93
  severityLevel: "High",
94
94
  title: "Detect Hardcoded Password Function Arguments",
95
- enabled: false,
95
+ enabled: true,
96
96
  languages: ["Python"],
97
97
  parameters: []
98
98
  },
@@ -114,15 +114,6 @@ var patterns_default = [
114
114
  languages: ["Python"],
115
115
  parameters: []
116
116
  },
117
- {
118
- id: "Bandit_B109",
119
- category: "Security",
120
- severityLevel: "Warning",
121
- title: "Detect Password Based Config Options Not Marked Secret",
122
- enabled: true,
123
- languages: ["Python"],
124
- parameters: []
125
- },
126
117
  {
127
118
  id: "Bandit_B110",
128
119
  category: "Security",
@@ -132,15 +123,6 @@ var patterns_default = [
132
123
  languages: ["Python"],
133
124
  parameters: []
134
125
  },
135
- {
136
- id: "Bandit_B111",
137
- category: "Security",
138
- severityLevel: "Warning",
139
- title: "Detect use of rootwrap running as root",
140
- enabled: true,
141
- languages: ["Python"],
142
- parameters: []
143
- },
144
126
  {
145
127
  id: "Bandit_B112",
146
128
  category: "Security",
@@ -252,8 +234,8 @@ var patterns_default = [
252
234
  {
253
235
  id: "Bandit_B309",
254
236
  category: "Security",
255
- severityLevel: "Warning",
256
- title: "Avoid Use of HTTPSConnection on Older Python Versions",
237
+ severityLevel: "High",
238
+ title: "Avoid usage of httplib.http.client HTTPSConnection on old Python versions",
257
239
  enabled: true,
258
240
  languages: ["Python"],
259
241
  parameters: []
@@ -351,8 +333,8 @@ var patterns_default = [
351
333
  {
352
334
  id: "Bandit_B320",
353
335
  category: "Security",
354
- severityLevel: "Warning",
355
- title: "Avoid Using Vulnerable lxml.etree XML Parsing Methods",
336
+ severityLevel: "High",
337
+ title: "Avoid unsafe lxml.etree usage",
356
338
  enabled: true,
357
339
  languages: ["Python"],
358
340
  parameters: []
@@ -370,8 +352,8 @@ var patterns_default = [
370
352
  id: "Bandit_B322",
371
353
  category: "Security",
372
354
  severityLevel: "High",
373
- title: "Avoid using input() in Python 2",
374
- enabled: false,
355
+ title: "Avoid use of input() in Python 2",
356
+ enabled: true,
375
357
  languages: ["Python"],
376
358
  parameters: []
377
359
  },
@@ -380,7 +362,7 @@ var patterns_default = [
380
362
  category: "Security",
381
363
  severityLevel: "Warning",
382
364
  title: "Avoid Using Unverified SSL Context",
383
- enabled: false,
365
+ enabled: true,
384
366
  languages: ["Python"],
385
367
  parameters: []
386
368
  },
@@ -389,16 +371,16 @@ var patterns_default = [
389
371
  category: "Security",
390
372
  severityLevel: "High",
391
373
  title: "Avoid Use of Insecure Hash Functions in hashlib",
392
- enabled: false,
374
+ enabled: true,
393
375
  languages: ["Python"],
394
376
  parameters: []
395
377
  },
396
378
  {
397
379
  id: "Bandit_B325",
398
380
  category: "Security",
399
- severityLevel: "Warning",
400
- title: "Avoid use of os.tempnam() and os.tmpnam()",
401
- enabled: false,
381
+ severityLevel: "High",
382
+ title: "Avoid use of os.tempnam/os.tmpnam",
383
+ enabled: true,
402
384
  languages: ["Python"],
403
385
  parameters: []
404
386
  },
@@ -486,8 +468,8 @@ var patterns_default = [
486
468
  {
487
469
  id: "Bandit_B410",
488
470
  category: "Security",
489
- severityLevel: "Warning",
490
- title: "Avoid Using Vulnerable XML Parsing Libraries (lxml)",
471
+ severityLevel: "High",
472
+ title: "Avoid importing lxml for untrusted XML parsing",
491
473
  enabled: true,
492
474
  languages: ["Python"],
493
475
  parameters: []
@@ -506,7 +488,7 @@ var patterns_default = [
506
488
  category: "Security",
507
489
  severityLevel: "High",
508
490
  title: "Avoid importing CGI handlers vulnerable to httpoxy",
509
- enabled: false,
491
+ enabled: true,
510
492
  languages: ["Python"],
511
493
  parameters: []
512
494
  },
@@ -515,7 +497,7 @@ var patterns_default = [
515
497
  category: "Security",
516
498
  severityLevel: "High",
517
499
  title: "Avoid Importing PyCrypto Library",
518
- enabled: false,
500
+ enabled: true,
519
501
  languages: ["Python"],
520
502
  parameters: []
521
503
  },
@@ -523,8 +505,17 @@ var patterns_default = [
523
505
  id: "Bandit_B414",
524
506
  category: "Security",
525
507
  severityLevel: "High",
526
- title: "Avoid Importing PyCryptodome Modules",
527
- enabled: false,
508
+ title: "Avoid importing pycryptodome (Cryptodome.*)",
509
+ enabled: true,
510
+ languages: ["Python"],
511
+ parameters: []
512
+ },
513
+ {
514
+ id: "Bandit_B415",
515
+ category: "Security",
516
+ severityLevel: "High",
517
+ title: "Avoid importing IPMI-related module (pyghmi)",
518
+ enabled: true,
528
519
  languages: ["Python"],
529
520
  parameters: []
530
521
  },
@@ -587,7 +578,7 @@ var patterns_default = [
587
578
  category: "Security",
588
579
  severityLevel: "High",
589
580
  title: "Avoid Disabling SSH Host Key Verification",
590
- enabled: false,
581
+ enabled: true,
591
582
  languages: ["Python"],
592
583
  parameters: []
593
584
  },
@@ -596,7 +587,7 @@ var patterns_default = [
596
587
  category: "Security",
597
588
  severityLevel: "Warning",
598
589
  title: "Avoid using insecure SNMP versions",
599
- enabled: false,
590
+ enabled: true,
600
591
  languages: ["Python"],
601
592
  parameters: []
602
593
  },
@@ -605,7 +596,7 @@ var patterns_default = [
605
596
  category: "Security",
606
597
  severityLevel: "Warning",
607
598
  title: "Avoid Weak SNMP Cryptography",
608
- enabled: false,
599
+ enabled: true,
609
600
  languages: ["Python"],
610
601
  parameters: []
611
602
  },
@@ -650,7 +641,7 @@ var patterns_default = [
650
641
  category: "Security",
651
642
  severityLevel: "Warning",
652
643
  title: "Avoid starting a process with a shell",
653
- enabled: false,
644
+ enabled: true,
654
645
  languages: ["Python"],
655
646
  parameters: []
656
647
  },
@@ -668,7 +659,7 @@ var patterns_default = [
668
659
  category: "Security",
669
660
  severityLevel: "Warning",
670
661
  title: "Avoid starting a process with a partial executable path",
671
- enabled: false,
662
+ enabled: true,
672
663
  languages: ["Python"],
673
664
  parameters: []
674
665
  },
@@ -695,7 +686,7 @@ var patterns_default = [
695
686
  category: "Security",
696
687
  severityLevel: "Warning",
697
688
  title: "Avoid Potential SQL Injection in Django extra() Function",
698
- enabled: false,
689
+ enabled: true,
699
690
  languages: ["Python"],
700
691
  parameters: []
701
692
  },
@@ -704,7 +695,7 @@ var patterns_default = [
704
695
  category: "Security",
705
696
  severityLevel: "Warning",
706
697
  title: "Avoid Use of RawSQL Function in Django",
707
- enabled: false,
698
+ enabled: true,
708
699
  languages: ["Python"],
709
700
  parameters: []
710
701
  },
@@ -713,10 +704,39 @@ var patterns_default = [
713
704
  category: "Security",
714
705
  severityLevel: "Warning",
715
706
  title: "Avoid insecure use of logging.config.listen",
716
- enabled: false,
707
+ enabled: true,
717
708
  languages: ["Python"],
718
709
  parameters: []
719
710
  },
711
+ {
712
+ id: "Bandit_B613",
713
+ category: "Security",
714
+ severityLevel: "High",
715
+ title: "Detect use of Unicode bidirectional (TrojanSource) control characters",
716
+ enabled: true,
717
+ languages: ["Python"],
718
+ parameters: []
719
+ },
720
+ {
721
+ id: "Bandit_B614",
722
+ category: "Security",
723
+ severityLevel: "High",
724
+ title: "Avoid unsafe PyTorch load",
725
+ enabled: true,
726
+ languages: ["Python"],
727
+ parameters: [],
728
+ tags: ["cwe502"]
729
+ },
730
+ {
731
+ id: "Bandit_B615",
732
+ category: "Security",
733
+ severityLevel: "Warning",
734
+ title: "Avoid unsafe Hugging Face Hub downloads (pin revisions)",
735
+ enabled: true,
736
+ languages: ["Python"],
737
+ parameters: [],
738
+ tags: ["huggingface", "supplychain"]
739
+ },
720
740
  {
721
741
  id: "Bandit_B701",
722
742
  category: "Security",
@@ -740,28 +760,56 @@ var patterns_default = [
740
760
  category: "Security",
741
761
  severityLevel: "Warning",
742
762
  title: "Avoid Potential XSS with django mark_safe Function",
743
- enabled: false,
763
+ enabled: true,
764
+ languages: ["Python"],
765
+ parameters: []
766
+ },
767
+ {
768
+ id: "Bandit_B704",
769
+ category: "Security",
770
+ severityLevel: "High",
771
+ title: "Avoid markupsafe.Markup on untrusted data",
772
+ enabled: true,
744
773
  languages: ["Python"],
745
774
  parameters: []
746
775
  }
747
776
  ];
748
777
 
778
+ // src/pattern-mappings.json
779
+ var pattern_mappings_default = {
780
+ flask: { prefixes: ["Bandit_B201", "Bandit_B701"] },
781
+ django: {
782
+ prefixes: ["Bandit_B308", "Bandit_B610", "Bandit_B611", "Bandit_B703"]
783
+ },
784
+ requests: { prefixes: ["Bandit_B113", "Bandit_B501"] },
785
+ httpx: { prefixes: ["Bandit_B113", "Bandit_B501"] },
786
+ jinja2: { prefixes: ["Bandit_B701"] },
787
+ mako: { prefixes: ["Bandit_B702"] },
788
+ paramiko: { prefixes: ["Bandit_B507", "Bandit_B601"] },
789
+ lxml: { prefixes: ["Bandit_B320", "Bandit_B410"] },
790
+ pyyaml: { prefixes: ["Bandit_B506"] },
791
+ pycrypto: { prefixes: ["Bandit_B413"] },
792
+ pycryptodome: { prefixes: ["Bandit_B414"] },
793
+ pysnmp: { prefixes: ["Bandit_B508", "Bandit_B509"] }
794
+ };
795
+
749
796
  // src/metadata.ts
750
797
  var descriptor = {
751
798
  id: "Bandit",
752
799
  displayName: "Bandit",
753
- preferredVersion: "1.8.3",
800
+ preferredVersion: "1.9.4",
754
801
  languages: ["Python"],
755
802
  filePatterns: ["**/*.py"],
756
803
  supportedOS: ["linux", "darwin", "win32"],
757
804
  supportedArch: ["x64", "arm64"],
758
- supportedRunners: ["local", "container"]
805
+ supportedRunners: ["local", "container"],
806
+ frameworkMappings: pattern_mappings_default
759
807
  };
760
808
 
761
809
  // src/adapter.ts
762
810
  var TOOL_ID = "Bandit";
763
811
  var ADAPTER_ID = "bandit-1";
764
- var PIP_PACKAGES = ["bandit==1.8.3"];
812
+ var PIP_PACKAGES = ["bandit==1.9.4"];
765
813
  var PYTHON_VERSION_RANGE = ">=3.8.0 <3.14.0";
766
814
  var PATTERN_META = new Map(
767
815
  patterns_default.map((p) => [
@@ -785,7 +833,14 @@ function mapConfidence(confidence) {
785
833
  return 1;
786
834
  }
787
835
  }
788
- var CONFIG_FILE_CANDIDATES = [".bandit", "bandit.yml", "pyproject.toml"];
836
+ var CONFIG_FILE_CANDIDATES = [
837
+ ".bandit",
838
+ "bandit.yml",
839
+ "pyproject.toml",
840
+ "bandit.yaml",
841
+ "bandit.toml",
842
+ "bandit.ini"
843
+ ];
789
844
  var PYPROJECT_BANDIT_SECTION = /^\[tool\.bandit(\.[\w-]+)*\]/m;
790
845
  async function pyprojectHasBanditSection(pyprojectPath) {
791
846
  try {
@@ -815,7 +870,7 @@ function buildMessage(result) {
815
870
  var adapter = {
816
871
  ...descriptor,
817
872
  patternsMetadata: patterns_default,
818
- compatibleVersions: ">=1.7.0",
873
+ compatibleVersions: ">=1.9.0",
819
874
  website: "https://bandit.readthedocs.io/",
820
875
  prerequisites: [
821
876
  {
@@ -832,7 +887,7 @@ var adapter = {
832
887
  * 1. Codacy-managed venv (`~/.codacy/runtimes/bandit-1/venv/bin/bandit`)
833
888
  * 2. Global PATH (`bandit`)
834
889
  *
835
- * Parses the version from `bandit --version` output like `bandit 1.8.3`.
890
+ * Parses the version from `bandit --version` output like `bandit 1.9.4`.
836
891
  */
837
892
  async checkAvailability(ctx) {
838
893
  ctx.logger.debug("Checking availability", { toolId: TOOL_ID });
@@ -904,7 +959,7 @@ var adapter = {
904
959
  * Installs bandit into an isolated Python virtual environment.
905
960
  *
906
961
  * Uses findPython -> ensureVenv -> pipInstall to create a dedicated venv
907
- * at `~/.codacy/runtimes/bandit-1/venv/` and install `bandit==1.8.3`.
962
+ * at `~/.codacy/runtimes/bandit-1/venv/` and install `bandit==1.9.4`.
908
963
  */
909
964
  async install(ctx) {
910
965
  ctx.logger.info("Starting install", { toolId: TOOL_ID });
@@ -916,7 +971,7 @@ var adapter = {
916
971
  toolId: TOOL_ID,
917
972
  phase: "requirementCheck",
918
973
  kind: "MissingPrerequisite",
919
- message: `Python (${PYTHON_VERSION_RANGE}) could not be found or downloaded. Bandit 1.8.x is incompatible with Python 3.14+.`,
974
+ message: `Python (${PYTHON_VERSION_RANGE}) could not be found or downloaded. Bandit 1.9.x is incompatible with Python 3.14+.`,
920
975
  level: "error"
921
976
  }
922
977
  };
@@ -950,7 +1005,7 @@ var adapter = {
950
1005
  /**
951
1006
  * Checks for bandit configuration files in the repository root.
952
1007
  *
953
- * Looks for `.bandit`, `bandit.yml`, or `pyproject.toml` (in that order).
1008
+ * Looks for `.bandit`, `bandit.yml`, `bandit.yaml`, `bandit.toml`, `bandit.ini`, or `pyproject.toml` (in that order).
954
1009
  * `pyproject.toml` only counts if it actually has a `[tool.bandit]` table —
955
1010
  * unlike the other two candidates, its mere existence says nothing about
956
1011
  * whether Bandit is configured (see {@link pyprojectHasBanditSection}).
@@ -961,7 +1016,7 @@ var adapter = {
961
1016
  const candidatePath = import_path.default.join(ctx.repositoryRoot, candidate);
962
1017
  try {
963
1018
  await import_promises.default.access(candidatePath);
964
- if (candidate === "pyproject.toml" && !await pyprojectHasBanditSection(candidatePath)) {
1019
+ if ((candidate === "pyproject.toml" || candidate === "bandit.toml") && !await pyprojectHasBanditSection(candidatePath)) {
965
1020
  continue;
966
1021
  }
967
1022
  ctx.logger.debug("Found local config", { toolId: TOOL_ID, path: candidatePath });
@@ -1004,7 +1059,7 @@ var adapter = {
1004
1059
  const useLocal = codacyConfig.useLocalConfigurationFile && codacyConfig.localConfigurationFile;
1005
1060
  if (useLocal) {
1006
1061
  const configPath = codacyConfig.localConfigurationFile;
1007
- if (configPath.endsWith(".bandit")) {
1062
+ if (configPath.endsWith(".bandit") || configPath.endsWith(".ini")) {
1008
1063
  args.push("--ini", configPath);
1009
1064
  } else {
1010
1065
  args.push("-c", configPath);
package/dist/metadata.js CHANGED
@@ -23,15 +23,36 @@ __export(metadata_exports, {
23
23
  descriptor: () => descriptor
24
24
  });
25
25
  module.exports = __toCommonJS(metadata_exports);
26
+
27
+ // src/pattern-mappings.json
28
+ var pattern_mappings_default = {
29
+ flask: { prefixes: ["Bandit_B201", "Bandit_B701"] },
30
+ django: {
31
+ prefixes: ["Bandit_B308", "Bandit_B610", "Bandit_B611", "Bandit_B703"]
32
+ },
33
+ requests: { prefixes: ["Bandit_B113", "Bandit_B501"] },
34
+ httpx: { prefixes: ["Bandit_B113", "Bandit_B501"] },
35
+ jinja2: { prefixes: ["Bandit_B701"] },
36
+ mako: { prefixes: ["Bandit_B702"] },
37
+ paramiko: { prefixes: ["Bandit_B507", "Bandit_B601"] },
38
+ lxml: { prefixes: ["Bandit_B320", "Bandit_B410"] },
39
+ pyyaml: { prefixes: ["Bandit_B506"] },
40
+ pycrypto: { prefixes: ["Bandit_B413"] },
41
+ pycryptodome: { prefixes: ["Bandit_B414"] },
42
+ pysnmp: { prefixes: ["Bandit_B508", "Bandit_B509"] }
43
+ };
44
+
45
+ // src/metadata.ts
26
46
  var descriptor = {
27
47
  id: "Bandit",
28
48
  displayName: "Bandit",
29
- preferredVersion: "1.8.3",
49
+ preferredVersion: "1.9.4",
30
50
  languages: ["Python"],
31
51
  filePatterns: ["**/*.py"],
32
52
  supportedOS: ["linux", "darwin", "win32"],
33
53
  supportedArch: ["x64", "arm64"],
34
- supportedRunners: ["local", "container"]
54
+ supportedRunners: ["local", "container"],
55
+ frameworkMappings: pattern_mappings_default
35
56
  };
36
57
  // Annotate the CommonJS export names for ESM import in node:
37
58
  0 && (module.exports = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/tools-bandit-1",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "Bandit adapter — CLI-mode Python security linter",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,7 +8,7 @@
8
8
  "dist"
9
9
  ],
10
10
  "dependencies": {
11
- "@codacy/tooling": "0.18.0"
11
+ "@codacy/tooling": "0.20.0"
12
12
  },
13
13
  "license": "MIT",
14
14
  "author": "Codacy <support@codacy.com> (https://www.codacy.com)",