sigreview 1.0.0__tar.gz

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.
Files changed (239) hide show
  1. sigreview-1.0.0/.gitignore +14 -0
  2. sigreview-1.0.0/CHANGELOG.md +51 -0
  3. sigreview-1.0.0/LICENSE +21 -0
  4. sigreview-1.0.0/PKG-INFO +245 -0
  5. sigreview-1.0.0/README.md +209 -0
  6. sigreview-1.0.0/ci/azure-pipelines.yml +49 -0
  7. sigreview-1.0.0/ci/bitbucket-pipelines.yml +27 -0
  8. sigreview-1.0.0/ci/github-actions.yml +34 -0
  9. sigreview-1.0.0/ci/gitlab-ci.yml +23 -0
  10. sigreview-1.0.0/pyproject.toml +71 -0
  11. sigreview-1.0.0/src/sigreview/__init__.py +3 -0
  12. sigreview-1.0.0/src/sigreview/__main__.py +6 -0
  13. sigreview-1.0.0/src/sigreview/baseline.py +37 -0
  14. sigreview-1.0.0/src/sigreview/cli.py +324 -0
  15. sigreview-1.0.0/src/sigreview/config.py +51 -0
  16. sigreview-1.0.0/src/sigreview/diff.py +49 -0
  17. sigreview-1.0.0/src/sigreview/finding.py +53 -0
  18. sigreview-1.0.0/src/sigreview/loader.py +227 -0
  19. sigreview-1.0.0/src/sigreview/normalize.py +110 -0
  20. sigreview-1.0.0/src/sigreview/notebook.py +165 -0
  21. sigreview-1.0.0/src/sigreview/remote.py +268 -0
  22. sigreview-1.0.0/src/sigreview/report/__init__.py +31 -0
  23. sigreview-1.0.0/src/sigreview/report/console.py +47 -0
  24. sigreview-1.0.0/src/sigreview/report/html.py +117 -0
  25. sigreview-1.0.0/src/sigreview/report/json.py +50 -0
  26. sigreview-1.0.0/src/sigreview/report/markdown.py +54 -0
  27. sigreview-1.0.0/src/sigreview/report/sarif.py +87 -0
  28. sigreview-1.0.0/src/sigreview/report/templates/fonts/OFL.txt +93 -0
  29. sigreview-1.0.0/src/sigreview/report/templates/fonts/RedHatMono-Regular.woff2 +0 -0
  30. sigreview-1.0.0/src/sigreview/report/templates/fonts/RedHatText-Bold.woff2 +0 -0
  31. sigreview-1.0.0/src/sigreview/report/templates/fonts/RedHatText-Regular.woff2 +0 -0
  32. sigreview-1.0.0/src/sigreview/report/templates/report.html.j2 +310 -0
  33. sigreview-1.0.0/src/sigreview/rules/__init__.py +74 -0
  34. sigreview-1.0.0/src/sigreview/rules/base.py +66 -0
  35. sigreview-1.0.0/src/sigreview/rules/dataflow.py +359 -0
  36. sigreview-1.0.0/src/sigreview/rules/dataframe.py +552 -0
  37. sigreview-1.0.0/src/sigreview/rules/deep_learning.py +281 -0
  38. sigreview-1.0.0/src/sigreview/rules/evaluation.py +210 -0
  39. sigreview-1.0.0/src/sigreview/rules/genai.py +875 -0
  40. sigreview-1.0.0/src/sigreview/rules/helpers.py +439 -0
  41. sigreview-1.0.0/src/sigreview/rules/leakage.py +280 -0
  42. sigreview-1.0.0/src/sigreview/rules/ml.py +424 -0
  43. sigreview-1.0.0/src/sigreview/rules/notebook.py +294 -0
  44. sigreview-1.0.0/src/sigreview/rules/project.py +386 -0
  45. sigreview-1.0.0/src/sigreview/rules/spark.py +311 -0
  46. sigreview-1.0.0/src/sigreview/rules/timeseries.py +303 -0
  47. sigreview-1.0.0/src/sigreview/runners/__init__.py +45 -0
  48. sigreview-1.0.0/src/sigreview/runners/base.py +51 -0
  49. sigreview-1.0.0/src/sigreview/runners/deptry.py +100 -0
  50. sigreview-1.0.0/src/sigreview/runners/detect_secrets.py +150 -0
  51. sigreview-1.0.0/src/sigreview/runners/pip_audit.py +84 -0
  52. sigreview-1.0.0/src/sigreview/runners/pyrefly.py +50 -0
  53. sigreview-1.0.0/src/sigreview/runners/ruff.py +161 -0
  54. sigreview-1.0.0/src/sigreview/runners/vulture.py +86 -0
  55. sigreview-1.0.0/src/sigreview/scan.py +119 -0
  56. sigreview-1.0.0/src/sigreview/theme.py +53 -0
  57. sigreview-1.0.0/tests/conftest.py +38 -0
  58. sigreview-1.0.0/tests/fixtures/databricks_notebook.py +29 -0
  59. sigreview-1.0.0/tests/fixtures/notebooks/NB001_bad.ipynb +52 -0
  60. sigreview-1.0.0/tests/fixtures/notebooks/NB001_good.ipynb +74 -0
  61. sigreview-1.0.0/tests/fixtures/notebooks/NB002_bad.ipynb +34 -0
  62. sigreview-1.0.0/tests/fixtures/notebooks/NB002_good.ipynb +43 -0
  63. sigreview-1.0.0/tests/fixtures/notebooks/NB003_bad.ipynb +26 -0
  64. sigreview-1.0.0/tests/fixtures/notebooks/NB003_good.ipynb +26 -0
  65. sigreview-1.0.0/tests/fixtures/notebooks/NB004_bad.ipynb +32 -0
  66. sigreview-1.0.0/tests/fixtures/notebooks/NB004_good.ipynb +33 -0
  67. sigreview-1.0.0/tests/fixtures/notebooks/NB005_good.ipynb +25 -0
  68. sigreview-1.0.0/tests/fixtures/notebooks/NB006_bad.ipynb +36 -0
  69. sigreview-1.0.0/tests/fixtures/notebooks/NB006_good.ipynb +32 -0
  70. sigreview-1.0.0/tests/fixtures/notebooks/NB007_bad.ipynb +23 -0
  71. sigreview-1.0.0/tests/fixtures/notebooks/NB007_good.ipynb +22 -0
  72. sigreview-1.0.0/tests/fixtures/notebooks/NB008_bad.ipynb +21 -0
  73. sigreview-1.0.0/tests/fixtures/notebooks/NB008_good.ipynb +21 -0
  74. sigreview-1.0.0/tests/fixtures/rules/DF001_bad.py +5 -0
  75. sigreview-1.0.0/tests/fixtures/rules/DF001_good.py +7 -0
  76. sigreview-1.0.0/tests/fixtures/rules/DF002_bad.py +6 -0
  77. sigreview-1.0.0/tests/fixtures/rules/DF002_good.py +7 -0
  78. sigreview-1.0.0/tests/fixtures/rules/DF003_bad.py +2 -0
  79. sigreview-1.0.0/tests/fixtures/rules/DF003_good.py +3 -0
  80. sigreview-1.0.0/tests/fixtures/rules/DF004_bad.py +6 -0
  81. sigreview-1.0.0/tests/fixtures/rules/DF004_good.py +8 -0
  82. sigreview-1.0.0/tests/fixtures/rules/DF005_bad.py +4 -0
  83. sigreview-1.0.0/tests/fixtures/rules/DF005_good.py +4 -0
  84. sigreview-1.0.0/tests/fixtures/rules/DF006_bad.py +5 -0
  85. sigreview-1.0.0/tests/fixtures/rules/DF006_good.py +6 -0
  86. sigreview-1.0.0/tests/fixtures/rules/DF007_bad.py +4 -0
  87. sigreview-1.0.0/tests/fixtures/rules/DF007_good.py +4 -0
  88. sigreview-1.0.0/tests/fixtures/rules/DF008_bad.py +7 -0
  89. sigreview-1.0.0/tests/fixtures/rules/DF008_good.py +7 -0
  90. sigreview-1.0.0/tests/fixtures/rules/DF009_bad.py +6 -0
  91. sigreview-1.0.0/tests/fixtures/rules/DF009_good.py +6 -0
  92. sigreview-1.0.0/tests/fixtures/rules/DF010_bad.py +4 -0
  93. sigreview-1.0.0/tests/fixtures/rules/DF010_good.py +4 -0
  94. sigreview-1.0.0/tests/fixtures/rules/DF011_bad.py +3 -0
  95. sigreview-1.0.0/tests/fixtures/rules/DF011_good.py +5 -0
  96. sigreview-1.0.0/tests/fixtures/rules/DF012_bad.py +3 -0
  97. sigreview-1.0.0/tests/fixtures/rules/DF012_good.py +3 -0
  98. sigreview-1.0.0/tests/fixtures/rules/DF013_bad.py +4 -0
  99. sigreview-1.0.0/tests/fixtures/rules/DF013_good.py +4 -0
  100. sigreview-1.0.0/tests/fixtures/rules/DF014_bad.py +3 -0
  101. sigreview-1.0.0/tests/fixtures/rules/DF014_good.py +4 -0
  102. sigreview-1.0.0/tests/fixtures/rules/DL001_bad.py +14 -0
  103. sigreview-1.0.0/tests/fixtures/rules/DL001_good.py +14 -0
  104. sigreview-1.0.0/tests/fixtures/rules/DL002_bad.py +9 -0
  105. sigreview-1.0.0/tests/fixtures/rules/DL002_good.py +9 -0
  106. sigreview-1.0.0/tests/fixtures/rules/DL003_bad.py +7 -0
  107. sigreview-1.0.0/tests/fixtures/rules/DL003_good.py +9 -0
  108. sigreview-1.0.0/tests/fixtures/rules/DL004_bad.py +5 -0
  109. sigreview-1.0.0/tests/fixtures/rules/DL004_good.py +5 -0
  110. sigreview-1.0.0/tests/fixtures/rules/DL005_bad.py +3 -0
  111. sigreview-1.0.0/tests/fixtures/rules/DL005_good.py +4 -0
  112. sigreview-1.0.0/tests/fixtures/rules/DL006_bad.py +3 -0
  113. sigreview-1.0.0/tests/fixtures/rules/DL006_good.py +10 -0
  114. sigreview-1.0.0/tests/fixtures/rules/DL007_bad.py +3 -0
  115. sigreview-1.0.0/tests/fixtures/rules/DL007_good.py +4 -0
  116. sigreview-1.0.0/tests/fixtures/rules/DS001_bad.py +8 -0
  117. sigreview-1.0.0/tests/fixtures/rules/DS001_good.py +29 -0
  118. sigreview-1.0.0/tests/fixtures/rules/DS002_bad.py +7 -0
  119. sigreview-1.0.0/tests/fixtures/rules/DS002_good.py +7 -0
  120. sigreview-1.0.0/tests/fixtures/rules/DS003_bad.py +7 -0
  121. sigreview-1.0.0/tests/fixtures/rules/DS003_good.py +8 -0
  122. sigreview-1.0.0/tests/fixtures/rules/DS004_bad.py +8 -0
  123. sigreview-1.0.0/tests/fixtures/rules/DS004_good.py +11 -0
  124. sigreview-1.0.0/tests/fixtures/rules/DS005_bad.py +5 -0
  125. sigreview-1.0.0/tests/fixtures/rules/DS005_good.py +5 -0
  126. sigreview-1.0.0/tests/fixtures/rules/DS006_bad.py +7 -0
  127. sigreview-1.0.0/tests/fixtures/rules/DS006_good.py +8 -0
  128. sigreview-1.0.0/tests/fixtures/rules/DS007_bad.py +7 -0
  129. sigreview-1.0.0/tests/fixtures/rules/DS007_good.py +12 -0
  130. sigreview-1.0.0/tests/fixtures/rules/DS008_bad.py +7 -0
  131. sigreview-1.0.0/tests/fixtures/rules/DS008_good.py +9 -0
  132. sigreview-1.0.0/tests/fixtures/rules/DS009_bad.py +11 -0
  133. sigreview-1.0.0/tests/fixtures/rules/DS009_good.py +12 -0
  134. sigreview-1.0.0/tests/fixtures/rules/DS010_bad.py +3 -0
  135. sigreview-1.0.0/tests/fixtures/rules/DS010_good.py +3 -0
  136. sigreview-1.0.0/tests/fixtures/rules/DS011_bad.py +7 -0
  137. sigreview-1.0.0/tests/fixtures/rules/DS011_good.py +10 -0
  138. sigreview-1.0.0/tests/fixtures/rules/DS012_bad.py +6 -0
  139. sigreview-1.0.0/tests/fixtures/rules/DS012_good.py +7 -0
  140. sigreview-1.0.0/tests/fixtures/rules/DS013_bad.py +6 -0
  141. sigreview-1.0.0/tests/fixtures/rules/DS013_good.py +7 -0
  142. sigreview-1.0.0/tests/fixtures/rules/DS014_bad.py +4 -0
  143. sigreview-1.0.0/tests/fixtures/rules/DS014_good.py +4 -0
  144. sigreview-1.0.0/tests/fixtures/rules/DS015_bad.py +6 -0
  145. sigreview-1.0.0/tests/fixtures/rules/DS015_good.py +8 -0
  146. sigreview-1.0.0/tests/fixtures/rules/EV001_bad.py +5 -0
  147. sigreview-1.0.0/tests/fixtures/rules/EV001_good.py +5 -0
  148. sigreview-1.0.0/tests/fixtures/rules/EV002_bad.py +5 -0
  149. sigreview-1.0.0/tests/fixtures/rules/EV002_good.py +5 -0
  150. sigreview-1.0.0/tests/fixtures/rules/EV003_bad.py +8 -0
  151. sigreview-1.0.0/tests/fixtures/rules/EV003_good.py +10 -0
  152. sigreview-1.0.0/tests/fixtures/rules/EV004_bad.py +6 -0
  153. sigreview-1.0.0/tests/fixtures/rules/EV004_good.py +5 -0
  154. sigreview-1.0.0/tests/fixtures/rules/LLM001_bad.py +5 -0
  155. sigreview-1.0.0/tests/fixtures/rules/LLM001_good.py +6 -0
  156. sigreview-1.0.0/tests/fixtures/rules/LLM002_bad.py +6 -0
  157. sigreview-1.0.0/tests/fixtures/rules/LLM002_good.py +7 -0
  158. sigreview-1.0.0/tests/fixtures/rules/LLM003_bad.py +4 -0
  159. sigreview-1.0.0/tests/fixtures/rules/LLM003_good.py +5 -0
  160. sigreview-1.0.0/tests/fixtures/rules/LLM004_bad.py +5 -0
  161. sigreview-1.0.0/tests/fixtures/rules/LLM004_good.py +10 -0
  162. sigreview-1.0.0/tests/fixtures/rules/LLM005_bad.py +4 -0
  163. sigreview-1.0.0/tests/fixtures/rules/LLM005_good.py +4 -0
  164. sigreview-1.0.0/tests/fixtures/rules/LLM006_bad.py +7 -0
  165. sigreview-1.0.0/tests/fixtures/rules/LLM006_good.py +5 -0
  166. sigreview-1.0.0/tests/fixtures/rules/LLM007_bad.py +2 -0
  167. sigreview-1.0.0/tests/fixtures/rules/LLM007_good.py +7 -0
  168. sigreview-1.0.0/tests/fixtures/rules/LLM008_bad.py +5 -0
  169. sigreview-1.0.0/tests/fixtures/rules/LLM008_good.py +7 -0
  170. sigreview-1.0.0/tests/fixtures/rules/LLM009_bad.py +4 -0
  171. sigreview-1.0.0/tests/fixtures/rules/LLM009_good.py +7 -0
  172. sigreview-1.0.0/tests/fixtures/rules/LLM010_bad.py +4 -0
  173. sigreview-1.0.0/tests/fixtures/rules/LLM010_good.py +4 -0
  174. sigreview-1.0.0/tests/fixtures/rules/LLM011_bad.py +11 -0
  175. sigreview-1.0.0/tests/fixtures/rules/LLM011_good.py +15 -0
  176. sigreview-1.0.0/tests/fixtures/rules/LLM012_bad.py +5 -0
  177. sigreview-1.0.0/tests/fixtures/rules/LLM012_good.py +4 -0
  178. sigreview-1.0.0/tests/fixtures/rules/LLM013_bad.py +2 -0
  179. sigreview-1.0.0/tests/fixtures/rules/LLM013_good.py +2 -0
  180. sigreview-1.0.0/tests/fixtures/rules/LLM015_bad.py +6 -0
  181. sigreview-1.0.0/tests/fixtures/rules/LLM015_good.py +7 -0
  182. sigreview-1.0.0/tests/fixtures/rules/LLM016_bad.py +4 -0
  183. sigreview-1.0.0/tests/fixtures/rules/LLM016_good.py +4 -0
  184. sigreview-1.0.0/tests/fixtures/rules/LLM017_bad.py +6 -0
  185. sigreview-1.0.0/tests/fixtures/rules/LLM017_good.py +6 -0
  186. sigreview-1.0.0/tests/fixtures/rules/LLM018_bad.py +5 -0
  187. sigreview-1.0.0/tests/fixtures/rules/LLM018_good.py +6 -0
  188. sigreview-1.0.0/tests/fixtures/rules/LLM019_bad.py +5 -0
  189. sigreview-1.0.0/tests/fixtures/rules/LLM019_good.py +5 -0
  190. sigreview-1.0.0/tests/fixtures/rules/PR006_bad.py +4 -0
  191. sigreview-1.0.0/tests/fixtures/rules/PR006_good.py +9 -0
  192. sigreview-1.0.0/tests/fixtures/rules/PR007_bad.py +4 -0
  193. sigreview-1.0.0/tests/fixtures/rules/PR007_good.py +6 -0
  194. sigreview-1.0.0/tests/fixtures/rules/SP001_bad.py +3 -0
  195. sigreview-1.0.0/tests/fixtures/rules/SP001_good.py +7 -0
  196. sigreview-1.0.0/tests/fixtures/rules/SP002_bad.py +4 -0
  197. sigreview-1.0.0/tests/fixtures/rules/SP002_good.py +3 -0
  198. sigreview-1.0.0/tests/fixtures/rules/SP003_bad.py +3 -0
  199. sigreview-1.0.0/tests/fixtures/rules/SP003_good.py +3 -0
  200. sigreview-1.0.0/tests/fixtures/rules/SP004_bad.py +9 -0
  201. sigreview-1.0.0/tests/fixtures/rules/SP004_good.py +10 -0
  202. sigreview-1.0.0/tests/fixtures/rules/SP005_bad.py +1 -0
  203. sigreview-1.0.0/tests/fixtures/rules/SP005_good.py +2 -0
  204. sigreview-1.0.0/tests/fixtures/rules/SP006_bad.py +6 -0
  205. sigreview-1.0.0/tests/fixtures/rules/SP006_good.py +6 -0
  206. sigreview-1.0.0/tests/fixtures/rules/SP007_bad.py +4 -0
  207. sigreview-1.0.0/tests/fixtures/rules/SP007_good.py +7 -0
  208. sigreview-1.0.0/tests/fixtures/rules/SP008_bad.py +1 -0
  209. sigreview-1.0.0/tests/fixtures/rules/SP008_good.py +2 -0
  210. sigreview-1.0.0/tests/fixtures/rules/TS001_bad.py +7 -0
  211. sigreview-1.0.0/tests/fixtures/rules/TS001_good.py +7 -0
  212. sigreview-1.0.0/tests/fixtures/rules/TS002_bad.py +6 -0
  213. sigreview-1.0.0/tests/fixtures/rules/TS002_good.py +6 -0
  214. sigreview-1.0.0/tests/fixtures/rules/TS003_bad.py +5 -0
  215. sigreview-1.0.0/tests/fixtures/rules/TS003_good.py +5 -0
  216. sigreview-1.0.0/tests/fixtures/rules/TS004_bad.py +8 -0
  217. sigreview-1.0.0/tests/fixtures/rules/TS004_good.py +8 -0
  218. sigreview-1.0.0/tests/fixtures/rules/TS005_bad.py +4 -0
  219. sigreview-1.0.0/tests/fixtures/rules/TS005_good.py +5 -0
  220. sigreview-1.0.0/tests/fixtures/rules/TS006_bad.py +4 -0
  221. sigreview-1.0.0/tests/fixtures/rules/TS006_good.py +4 -0
  222. sigreview-1.0.0/tests/fixtures/rules/TS007_bad.py +6 -0
  223. sigreview-1.0.0/tests/fixtures/rules/TS007_good.py +7 -0
  224. sigreview-1.0.0/tests/fixtures/sample_project/.env +1 -0
  225. sigreview-1.0.0/tests/fixtures/sample_project/notebooks/explore.ipynb +69 -0
  226. sigreview-1.0.0/tests/fixtures/sample_project/requirements.txt +4 -0
  227. sigreview-1.0.0/tests/fixtures/sample_project/src/features.py +23 -0
  228. sigreview-1.0.0/tests/fixtures/sample_project/src/train.py +24 -0
  229. sigreview-1.0.0/tests/test_ci_files.py +17 -0
  230. sigreview-1.0.0/tests/test_cli.py +69 -0
  231. sigreview-1.0.0/tests/test_databricks.py +38 -0
  232. sigreview-1.0.0/tests/test_loader.py +44 -0
  233. sigreview-1.0.0/tests/test_normalize.py +72 -0
  234. sigreview-1.0.0/tests/test_pr_options.py +113 -0
  235. sigreview-1.0.0/tests/test_project_rules.py +97 -0
  236. sigreview-1.0.0/tests/test_remote.py +113 -0
  237. sigreview-1.0.0/tests/test_report.py +74 -0
  238. sigreview-1.0.0/tests/test_ruff_runner.py +45 -0
  239. sigreview-1.0.0/tests/test_rules.py +47 -0
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .venv/
5
+ venv/
6
+ build/
7
+ dist/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ sigreview_report.html
11
+ sigreview_findings.json
12
+ sigreview_findings.sarif
13
+ sigreview_summary.md
14
+ .sigreview/
@@ -0,0 +1,51 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ - 61 new data science rules, 90 in total. New areas: Evaluation (EV), Time series (TS),
6
+ Deep learning (DL) and GenAI / LLM apps (LLM, following the OWASP Top 10 for LLM apps).
7
+ More rules for ML leakage (DS011-DS015), pandas 3 (DF007-DF014), Spark (SP003-SP008),
8
+ notebooks (NB006-NB008) and reproducibility (PR007-PR008).
9
+ - `scan` needs `-f "folder"` or `-r "repo link"`. Plain `sigreview scan .` is gone.
10
+ - `-r` clones GitHub, Azure DevOps, Bitbucket and GitLab repos (https or git@), scans them and
11
+ deletes the copy. `--branch` picks the branch. Private repos use your own git login, or
12
+ `SIGREVIEW_GIT_TOKEN` in CI. The report shows the repo link and commit.
13
+ - `--diff main` shows only findings in files changed since a branch, for pull requests.
14
+ - `sigreview baseline` records today's findings; later scans hide them and show only new ones.
15
+ - `--fail-on high|medium|low|none` sets what fails the scan.
16
+ - Databricks notebooks saved as `.py` files are read as notebooks, with cell numbers.
17
+ - Two more outputs: `sigreview_findings.sarif` (inline findings on GitHub and Azure DevOps PRs)
18
+ and `sigreview_summary.md` (a short PR comment).
19
+ - Ready-made CI templates for GitLab, Azure Pipelines, GitHub Actions and Bitbucket, and a pre-commit hook.
20
+ - Reports are written to a `scan_result` folder.
21
+ - `-o` writes the reports to another folder. `doctor` also checks Git.
22
+
23
+ ## 0.2.1
24
+
25
+ - Report in Sigmoid's colours: white, black and crimson. Crimson marks the brand and high severity only.
26
+ - The large headline is gone. One line under the project name gives the counts and pass or fail.
27
+ - The name is shown as SigReview. The command is still `sigreview`.
28
+ - A data science rule ID opens its explanation under the finding. The rules section at the bottom is gone.
29
+
30
+ ## 0.2.0
31
+
32
+ Less noise and a new report.
33
+
34
+ - Style nits no longer get one finding per line. Several statements or imports on one line,
35
+ missing docstrings and legacy `np.random` calls are each reported once for the project, with
36
+ a count and the files most affected (`formatting`, `docstrings`, `legacy-random`).
37
+ - Complexity (C901) is reported only above 30, as low. The message says under 10 is ideal.
38
+ - No longer reported: f-string without placeholders (F541), import not at the top (E402).
39
+ - sigreview's own rules are named "Data science rules". In the JSON their `tool` is `ds-rules`
40
+ (was `sigreview`), and every check has a `label`.
41
+ - New HTML report: verdict first, findings grouped by severity and file, fonts embedded.
42
+
43
+ ## 0.1.0
44
+
45
+ First release.
46
+
47
+ - `sigreview scan`, `sigreview doctor`, `sigreview rules`
48
+ - 29 rules: DS001-DS010, DF001-DF006, SP001-SP002, NB001-NB005, PR001-PR006
49
+ - Wrapped tools: Ruff, Pyrefly, Vulture, deptry, pip-audit, detect-secrets
50
+ - HTML report and JSON findings written into the scanned folder
51
+ - Inline `# sigreview: ignore[ID]` and `[tool.sigreview]` ignore / exclude settings
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Subhabrat Biswal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,245 @@
1
+ Metadata-Version: 2.5
2
+ Name: sigreview
3
+ Version: 1.0.0
4
+ Summary: Deterministic code review for data science, ML and GenAI projects
5
+ Author: Subhabrat Biswal
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ License-File: src/sigreview/report/templates/fonts/OFL.txt
9
+ Keywords: code review,data leakage,data science,databricks,linter,llm,machine learning,notebooks
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: deptry<1,>=0.20
22
+ Requires-Dist: detect-secrets<2,>=1.5
23
+ Requires-Dist: jinja2<4,>=3.1
24
+ Requires-Dist: markupsafe<4,>=2
25
+ Requires-Dist: pip-audit<3,>=2.7
26
+ Requires-Dist: pyrefly<2,>=1.0
27
+ Requires-Dist: rich<16,>=13
28
+ Requires-Dist: ruff<0.18,>=0.16
29
+ Requires-Dist: tomli>=2; python_version < '3.11'
30
+ Requires-Dist: typer<1,>=0.12
31
+ Requires-Dist: vulture<3,>=2.11
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=8; extra == 'dev'
34
+ Requires-Dist: pyyaml>=6; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # SigReview
38
+
39
+ Deterministic code review for data science, ML and GenAI projects. One install, one command, one report.
40
+
41
+ ```bash
42
+ pip install sigreview
43
+ sigreview scan -f ./my_project # a local folder
44
+ sigreview scan -r https://github.com/org/repo # a Git repo link (GitHub, GitLab, Azure DevOps, Bitbucket)
45
+ ```
46
+
47
+ SigReview reads every `.py`, `.ipynb` and Databricks notebook in the project, runs its own 90
48
+ data science rules plus six proven tools, and writes four files into a `scan_result` folder:
49
+
50
+ - `sigreview_report.html`: the report for people
51
+ - `sigreview_findings.json`: the same findings for machines (CI, the review agent)
52
+ - `sigreview_findings.sarif`: for inline findings on GitHub and Azure DevOps pull requests
53
+ - `sigreview_summary.md`: a short summary to post as a PR comment
54
+
55
+ Nothing in your project is executed. SigReview only reads code.
56
+
57
+ ## Commands
58
+
59
+ | Command | What it does |
60
+ |---|---|
61
+ | `sigreview scan -f "folder"` | Scan a local folder. Reports go to `folder/scan_result/` |
62
+ | `sigreview scan -r "repo link"` | Clone a repo, scan it, delete the copy. Reports go to `./scan_result/` |
63
+ | `sigreview baseline -f "folder"` | Record today's findings as known, so later scans show only new ones |
64
+ | `sigreview doctor` | Check that every wrapped tool and Git are installed, with versions |
65
+ | `sigreview rules [ID]` | List every rule, or show one in full: `sigreview rules DS001` |
66
+ | `sigreview --version` | Show the version |
67
+
68
+ Options for `scan`:
69
+
70
+ | Option | What it does |
71
+ |---|---|
72
+ | `-b, --branch NAME` | With `-r`: the branch to scan. Default: the repo's default branch |
73
+ | `-d, --diff BRANCH` | Only show findings in files changed since that branch, e.g. `--diff main` |
74
+ | `--fail-on LEVEL` | `high` (default), `medium`, `low` or `none`: the lowest severity that fails the scan |
75
+ | `--baseline FILE` | Baseline file to use. Default: `.sigreview-baseline.json` in the project, if present |
76
+ | `-o, --output FOLDER` | Write the reports somewhere other than `scan_result/` |
77
+
78
+ `scan` exits with 1 when a finding reaches the `--fail-on` level, so it can gate CI, and 2 on usage errors.
79
+
80
+ | Severity | Meaning |
81
+ |---|---|
82
+ | High | Proven problem. Fix before merging. |
83
+ | Medium | Likely bug or risky pattern. Someone should look. |
84
+ | Low | Cleanup and readability. |
85
+
86
+ ## Scanning a repo link
87
+
88
+ `-r` works with GitHub, Azure DevOps, Bitbucket and GitLab (and any other Git host), with
89
+ `https://...` or `git@...` links:
90
+
91
+ ```bash
92
+ sigreview scan -r https://github.com/org/churn-model
93
+ sigreview scan -r git@github.com:org/churn-model.git --branch feature/new-features
94
+ sigreview scan -r https://dev.azure.com/org/project/_git/routing
95
+ sigreview scan -r https://bitbucket.org/team/forecast
96
+ ```
97
+
98
+ **Login.** Public repos need nothing. For private repos:
99
+
100
+ 1. **Your own Git login** is used by default: whatever already works for `git clone` on your
101
+ machine (saved HTTPS login, Git Credential Manager, or your SSH key for `git@` links).
102
+ 2. **A token**, for CI or a machine without a saved login: set `SIGREVIEW_GIT_TOKEN`.
103
+ It is used instead of your own login when set.
104
+ 3. `SIGREVIEW_GIT_USER` only if your host needs a specific username with the token.
105
+ The defaults work for GitHub, Azure DevOps, Bitbucket and GitLab tokens.
106
+
107
+ | Host | Token to create | Access it needs |
108
+ |---|---|---|
109
+ | GitHub | Fine-grained personal access token | Contents: Read-only, on the repos to scan |
110
+ | Azure DevOps | Personal access token (PAT) | Code: Read |
111
+ | Bitbucket | Repository access token, or API token | Repositories: Read |
112
+ | GitLab | Personal or project access token | read_repository |
113
+
114
+ ```bash
115
+ export SIGREVIEW_GIT_TOKEN=... # Windows PowerShell: $env:SIGREVIEW_GIT_TOKEN="..."
116
+ sigreview scan -r https://dev.azure.com/org/project/_git/routing
117
+ ```
118
+
119
+ Inside a CI pipeline the platform's own token is picked up automatically: `GITHUB_TOKEN`,
120
+ `SYSTEM_ACCESSTOKEN` (Azure Pipelines), `BITBUCKET_TOKEN` or `CI_JOB_TOKEN` (GitLab).
121
+
122
+ The token is never accepted on the command line (it would end up in your shell history), is
123
+ passed to Git without being written to disk, and is masked in every message.
124
+
125
+ ## Reviewing pull requests
126
+
127
+ ```bash
128
+ sigreview scan -f . --diff main # only files changed since main
129
+ sigreview scan -f . --diff origin/main --fail-on medium
130
+ ```
131
+
132
+ **Old projects.** Run `sigreview baseline -f .` once and commit `.sigreview-baseline.json`.
133
+ Every later scan hides those known findings and shows only new ones. Run it again whenever
134
+ you want to accept the current state.
135
+
136
+ ## What it checks
137
+
138
+ **Data science rules** (SigReview's own, run `sigreview rules` for the full list)
139
+
140
+ | Area | Rules |
141
+ |---|---|
142
+ | Machine learning | DS001-DS015: leakage before the split (sklearn and pandas), fitting on test data, target left in features, target-based features, resampling before the split, early stopping on the test set, the same entity in train and test, separate encoding of train and test, unscaled features for KNN/SVM, missing seeds, PyTorch `zero_grad` / `eval()` / unsafe `torch.load` |
143
+ | Evaluation | EV001-EV004: probability metrics on hard labels, swapped metric arguments, model chosen on the test set, scoring on training data only |
144
+ | Time series | TS001-TS007: shuffled splits, windows that include the current target, centred windows, backward fill, future values as features, no gap for multi-step forecasts, scoring on the tail of the fitted series |
145
+ | Deep learning | DL001-DL007: softmax before a logits loss, loss tensors accumulated, wrong step order, softmax without `dim`, unshuffled training loader, `model.forward()`, fine-tuning evaluated on its training data |
146
+ | DataFrames | DF001-DF014: chained assignment, results thrown away, `iterrows()` writes, pandas 2.0 removals, `merge` without `validate=`, `concat` in a loop, `inplace=True` assigned, index misalignment, `.loc[i]` after filtering, pandas 3 string and datetime changes, ignored conversion errors, ambiguous dates, NaN turned into "nan" |
147
+ | Spark | SP001-SP008: `collect()` / `toPandas()` without `limit()`, `withColumn` in a loop, `== None`, UDFs without a return type, static partition overwrite, actions in a loop, `monotonically_increasing_id` as row number, single-partition writes |
148
+ | Notebooks | NB001-NB008: names used before the cell that defines them, out-of-order runs, `!pip install`, saved errors, large outputs, data tables and secrets saved in outputs, `%run` |
149
+ | GenAI and LLM apps | LLM001-LLM019: model output run as code, SQL or HTML, agents with shell or code tools, remote code from model hubs, unsafe pickles, user text in the system prompt, whole DataFrames in prompts, unguarded JSON parsing, no output limit, no timeout or unbounded retries, one call per row, unpinned model versions, mixed embedding models, unbounded chat history, removed SDK APIs, prompts in logs, right padding for generation, chunks longer than the embedding model |
150
+ | Project | PR001-PR008: no dependency file, unpinned versions, no tests, large data files or secret files committed, hardcoded absolute paths, training window tied to today's date, models saved without library versions |
151
+
152
+ **Wrapped tools** (installed with SigReview)
153
+
154
+ | Tool | Checks |
155
+ |---|---|
156
+ | Ruff | Likely bugs, risky security patterns, unused imports and variables, functions with a complexity above 30 |
157
+ | Pyrefly | Type errors: wrong arguments, missing attributes |
158
+ | Vulture | Functions and classes nothing calls, unreachable code |
159
+ | deptry | Imports missing from the dependency file, unused dependencies |
160
+ | pip-audit | Known vulnerabilities in pinned packages (needs internet) |
161
+ | detect-secrets | API keys, tokens and passwords in files |
162
+
163
+ Style nits do not get one finding per line. Each kind is reported once for the whole project,
164
+ with a count and the files most affected: `formatting`, `docstrings` and `legacy-random`.
165
+
166
+ **Databricks.** Notebooks exported to Git as `.py` files (they start with
167
+ `# Databricks notebook source`) are read as notebooks: the notebook rules run, and every
168
+ finding shows its cell number.
169
+
170
+ ## Silencing a finding
171
+
172
+ On the line itself:
173
+
174
+ ```python
175
+ df = pd.read_csv("/Users/anna/data.csv") # sigreview: ignore[PR006]
176
+ ```
177
+
178
+ For the whole project, in `pyproject.toml`:
179
+
180
+ ```toml
181
+ [tool.sigreview]
182
+ ignore = ["PR003", "docstrings"] # rule IDs to switch off
183
+ exclude = ["legacy/", "*_old.py"] # paths to skip
184
+ ```
185
+
186
+ ## Use in CI
187
+
188
+ Ready-made setups are in the [`ci/`](ci) folder: copy the one for your platform.
189
+
190
+ **GitLab** ([`ci/gitlab-ci.yml`](ci/gitlab-ci.yml)): scans the files changed in each merge request
191
+ and keeps the reports as job artifacts.
192
+
193
+ **Azure Pipelines** ([`ci/azure-pipelines.yml`](ci/azure-pipelines.yml)), **GitHub Actions**
194
+ ([`ci/github-actions.yml`](ci/github-actions.yml)) and **Bitbucket**
195
+ ([`ci/bitbucket-pipelines.yml`](ci/bitbucket-pipelines.yml)) work the same way.
196
+
197
+ **Any CI**, in two lines:
198
+
199
+ ```bash
200
+ pip install sigreview
201
+ sigreview scan -f . --diff origin/main --fail-on high
202
+ ```
203
+
204
+ **pre-commit**, with sigreview installed in your environment:
205
+
206
+ ```yaml
207
+ # .pre-commit-config.yaml
208
+ repos:
209
+ - repo: local
210
+ hooks:
211
+ - id: sigreview
212
+ name: sigreview
213
+ entry: sigreview scan -f . --diff main
214
+ language: system
215
+ pass_filenames: false
216
+ always_run: true
217
+ stages: [pre-push]
218
+ ```
219
+
220
+ Add `scan_result/` to `.gitignore` in projects you scan.
221
+
222
+ Colour and symbols switch off automatically in CI logs, pipes and when `NO_COLOR` is set.
223
+
224
+ ## Development
225
+
226
+ ```bash
227
+ python -m venv .venv
228
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
229
+ pip install -e ".[dev]"
230
+ pytest
231
+ sigreview scan -f tests/fixtures/sample_project
232
+ ```
233
+
234
+ Try it on the sample project, then open `tests/fixtures/sample_project/scan_result/sigreview_report.html`
235
+ in a browser. The sample has one or more examples of most rules.
236
+
237
+ Colours live in `src/sigreview/theme.py`: `SIGMOID_RED` for the terminal, `REPORT_COLOURS` for the report.
238
+ The report embeds the Red Hat Text and Red Hat Mono fonts (SIL Open Font License, see
239
+ `src/sigreview/report/templates/fonts/OFL.txt`), so it looks the same offline and on every machine.
240
+
241
+ Adding a rule: write a function with the `@rule(...)` decorator in the right file under
242
+ `src/sigreview/rules/`, then add `tests/fixtures/rules/<ID>_bad.py` and `<ID>_good.py`.
243
+ The tests check that every rule fires on its bad file and stays silent on its good one.
244
+
245
+ Author: Subhabrat Biswal
@@ -0,0 +1,209 @@
1
+ # SigReview
2
+
3
+ Deterministic code review for data science, ML and GenAI projects. One install, one command, one report.
4
+
5
+ ```bash
6
+ pip install sigreview
7
+ sigreview scan -f ./my_project # a local folder
8
+ sigreview scan -r https://github.com/org/repo # a Git repo link (GitHub, GitLab, Azure DevOps, Bitbucket)
9
+ ```
10
+
11
+ SigReview reads every `.py`, `.ipynb` and Databricks notebook in the project, runs its own 90
12
+ data science rules plus six proven tools, and writes four files into a `scan_result` folder:
13
+
14
+ - `sigreview_report.html`: the report for people
15
+ - `sigreview_findings.json`: the same findings for machines (CI, the review agent)
16
+ - `sigreview_findings.sarif`: for inline findings on GitHub and Azure DevOps pull requests
17
+ - `sigreview_summary.md`: a short summary to post as a PR comment
18
+
19
+ Nothing in your project is executed. SigReview only reads code.
20
+
21
+ ## Commands
22
+
23
+ | Command | What it does |
24
+ |---|---|
25
+ | `sigreview scan -f "folder"` | Scan a local folder. Reports go to `folder/scan_result/` |
26
+ | `sigreview scan -r "repo link"` | Clone a repo, scan it, delete the copy. Reports go to `./scan_result/` |
27
+ | `sigreview baseline -f "folder"` | Record today's findings as known, so later scans show only new ones |
28
+ | `sigreview doctor` | Check that every wrapped tool and Git are installed, with versions |
29
+ | `sigreview rules [ID]` | List every rule, or show one in full: `sigreview rules DS001` |
30
+ | `sigreview --version` | Show the version |
31
+
32
+ Options for `scan`:
33
+
34
+ | Option | What it does |
35
+ |---|---|
36
+ | `-b, --branch NAME` | With `-r`: the branch to scan. Default: the repo's default branch |
37
+ | `-d, --diff BRANCH` | Only show findings in files changed since that branch, e.g. `--diff main` |
38
+ | `--fail-on LEVEL` | `high` (default), `medium`, `low` or `none`: the lowest severity that fails the scan |
39
+ | `--baseline FILE` | Baseline file to use. Default: `.sigreview-baseline.json` in the project, if present |
40
+ | `-o, --output FOLDER` | Write the reports somewhere other than `scan_result/` |
41
+
42
+ `scan` exits with 1 when a finding reaches the `--fail-on` level, so it can gate CI, and 2 on usage errors.
43
+
44
+ | Severity | Meaning |
45
+ |---|---|
46
+ | High | Proven problem. Fix before merging. |
47
+ | Medium | Likely bug or risky pattern. Someone should look. |
48
+ | Low | Cleanup and readability. |
49
+
50
+ ## Scanning a repo link
51
+
52
+ `-r` works with GitHub, Azure DevOps, Bitbucket and GitLab (and any other Git host), with
53
+ `https://...` or `git@...` links:
54
+
55
+ ```bash
56
+ sigreview scan -r https://github.com/org/churn-model
57
+ sigreview scan -r git@github.com:org/churn-model.git --branch feature/new-features
58
+ sigreview scan -r https://dev.azure.com/org/project/_git/routing
59
+ sigreview scan -r https://bitbucket.org/team/forecast
60
+ ```
61
+
62
+ **Login.** Public repos need nothing. For private repos:
63
+
64
+ 1. **Your own Git login** is used by default: whatever already works for `git clone` on your
65
+ machine (saved HTTPS login, Git Credential Manager, or your SSH key for `git@` links).
66
+ 2. **A token**, for CI or a machine without a saved login: set `SIGREVIEW_GIT_TOKEN`.
67
+ It is used instead of your own login when set.
68
+ 3. `SIGREVIEW_GIT_USER` only if your host needs a specific username with the token.
69
+ The defaults work for GitHub, Azure DevOps, Bitbucket and GitLab tokens.
70
+
71
+ | Host | Token to create | Access it needs |
72
+ |---|---|---|
73
+ | GitHub | Fine-grained personal access token | Contents: Read-only, on the repos to scan |
74
+ | Azure DevOps | Personal access token (PAT) | Code: Read |
75
+ | Bitbucket | Repository access token, or API token | Repositories: Read |
76
+ | GitLab | Personal or project access token | read_repository |
77
+
78
+ ```bash
79
+ export SIGREVIEW_GIT_TOKEN=... # Windows PowerShell: $env:SIGREVIEW_GIT_TOKEN="..."
80
+ sigreview scan -r https://dev.azure.com/org/project/_git/routing
81
+ ```
82
+
83
+ Inside a CI pipeline the platform's own token is picked up automatically: `GITHUB_TOKEN`,
84
+ `SYSTEM_ACCESSTOKEN` (Azure Pipelines), `BITBUCKET_TOKEN` or `CI_JOB_TOKEN` (GitLab).
85
+
86
+ The token is never accepted on the command line (it would end up in your shell history), is
87
+ passed to Git without being written to disk, and is masked in every message.
88
+
89
+ ## Reviewing pull requests
90
+
91
+ ```bash
92
+ sigreview scan -f . --diff main # only files changed since main
93
+ sigreview scan -f . --diff origin/main --fail-on medium
94
+ ```
95
+
96
+ **Old projects.** Run `sigreview baseline -f .` once and commit `.sigreview-baseline.json`.
97
+ Every later scan hides those known findings and shows only new ones. Run it again whenever
98
+ you want to accept the current state.
99
+
100
+ ## What it checks
101
+
102
+ **Data science rules** (SigReview's own, run `sigreview rules` for the full list)
103
+
104
+ | Area | Rules |
105
+ |---|---|
106
+ | Machine learning | DS001-DS015: leakage before the split (sklearn and pandas), fitting on test data, target left in features, target-based features, resampling before the split, early stopping on the test set, the same entity in train and test, separate encoding of train and test, unscaled features for KNN/SVM, missing seeds, PyTorch `zero_grad` / `eval()` / unsafe `torch.load` |
107
+ | Evaluation | EV001-EV004: probability metrics on hard labels, swapped metric arguments, model chosen on the test set, scoring on training data only |
108
+ | Time series | TS001-TS007: shuffled splits, windows that include the current target, centred windows, backward fill, future values as features, no gap for multi-step forecasts, scoring on the tail of the fitted series |
109
+ | Deep learning | DL001-DL007: softmax before a logits loss, loss tensors accumulated, wrong step order, softmax without `dim`, unshuffled training loader, `model.forward()`, fine-tuning evaluated on its training data |
110
+ | DataFrames | DF001-DF014: chained assignment, results thrown away, `iterrows()` writes, pandas 2.0 removals, `merge` without `validate=`, `concat` in a loop, `inplace=True` assigned, index misalignment, `.loc[i]` after filtering, pandas 3 string and datetime changes, ignored conversion errors, ambiguous dates, NaN turned into "nan" |
111
+ | Spark | SP001-SP008: `collect()` / `toPandas()` without `limit()`, `withColumn` in a loop, `== None`, UDFs without a return type, static partition overwrite, actions in a loop, `monotonically_increasing_id` as row number, single-partition writes |
112
+ | Notebooks | NB001-NB008: names used before the cell that defines them, out-of-order runs, `!pip install`, saved errors, large outputs, data tables and secrets saved in outputs, `%run` |
113
+ | GenAI and LLM apps | LLM001-LLM019: model output run as code, SQL or HTML, agents with shell or code tools, remote code from model hubs, unsafe pickles, user text in the system prompt, whole DataFrames in prompts, unguarded JSON parsing, no output limit, no timeout or unbounded retries, one call per row, unpinned model versions, mixed embedding models, unbounded chat history, removed SDK APIs, prompts in logs, right padding for generation, chunks longer than the embedding model |
114
+ | Project | PR001-PR008: no dependency file, unpinned versions, no tests, large data files or secret files committed, hardcoded absolute paths, training window tied to today's date, models saved without library versions |
115
+
116
+ **Wrapped tools** (installed with SigReview)
117
+
118
+ | Tool | Checks |
119
+ |---|---|
120
+ | Ruff | Likely bugs, risky security patterns, unused imports and variables, functions with a complexity above 30 |
121
+ | Pyrefly | Type errors: wrong arguments, missing attributes |
122
+ | Vulture | Functions and classes nothing calls, unreachable code |
123
+ | deptry | Imports missing from the dependency file, unused dependencies |
124
+ | pip-audit | Known vulnerabilities in pinned packages (needs internet) |
125
+ | detect-secrets | API keys, tokens and passwords in files |
126
+
127
+ Style nits do not get one finding per line. Each kind is reported once for the whole project,
128
+ with a count and the files most affected: `formatting`, `docstrings` and `legacy-random`.
129
+
130
+ **Databricks.** Notebooks exported to Git as `.py` files (they start with
131
+ `# Databricks notebook source`) are read as notebooks: the notebook rules run, and every
132
+ finding shows its cell number.
133
+
134
+ ## Silencing a finding
135
+
136
+ On the line itself:
137
+
138
+ ```python
139
+ df = pd.read_csv("/Users/anna/data.csv") # sigreview: ignore[PR006]
140
+ ```
141
+
142
+ For the whole project, in `pyproject.toml`:
143
+
144
+ ```toml
145
+ [tool.sigreview]
146
+ ignore = ["PR003", "docstrings"] # rule IDs to switch off
147
+ exclude = ["legacy/", "*_old.py"] # paths to skip
148
+ ```
149
+
150
+ ## Use in CI
151
+
152
+ Ready-made setups are in the [`ci/`](ci) folder: copy the one for your platform.
153
+
154
+ **GitLab** ([`ci/gitlab-ci.yml`](ci/gitlab-ci.yml)): scans the files changed in each merge request
155
+ and keeps the reports as job artifacts.
156
+
157
+ **Azure Pipelines** ([`ci/azure-pipelines.yml`](ci/azure-pipelines.yml)), **GitHub Actions**
158
+ ([`ci/github-actions.yml`](ci/github-actions.yml)) and **Bitbucket**
159
+ ([`ci/bitbucket-pipelines.yml`](ci/bitbucket-pipelines.yml)) work the same way.
160
+
161
+ **Any CI**, in two lines:
162
+
163
+ ```bash
164
+ pip install sigreview
165
+ sigreview scan -f . --diff origin/main --fail-on high
166
+ ```
167
+
168
+ **pre-commit**, with sigreview installed in your environment:
169
+
170
+ ```yaml
171
+ # .pre-commit-config.yaml
172
+ repos:
173
+ - repo: local
174
+ hooks:
175
+ - id: sigreview
176
+ name: sigreview
177
+ entry: sigreview scan -f . --diff main
178
+ language: system
179
+ pass_filenames: false
180
+ always_run: true
181
+ stages: [pre-push]
182
+ ```
183
+
184
+ Add `scan_result/` to `.gitignore` in projects you scan.
185
+
186
+ Colour and symbols switch off automatically in CI logs, pipes and when `NO_COLOR` is set.
187
+
188
+ ## Development
189
+
190
+ ```bash
191
+ python -m venv .venv
192
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
193
+ pip install -e ".[dev]"
194
+ pytest
195
+ sigreview scan -f tests/fixtures/sample_project
196
+ ```
197
+
198
+ Try it on the sample project, then open `tests/fixtures/sample_project/scan_result/sigreview_report.html`
199
+ in a browser. The sample has one or more examples of most rules.
200
+
201
+ Colours live in `src/sigreview/theme.py`: `SIGMOID_RED` for the terminal, `REPORT_COLOURS` for the report.
202
+ The report embeds the Red Hat Text and Red Hat Mono fonts (SIL Open Font License, see
203
+ `src/sigreview/report/templates/fonts/OFL.txt`), so it looks the same offline and on every machine.
204
+
205
+ Adding a rule: write a function with the `@rule(...)` decorator in the right file under
206
+ `src/sigreview/rules/`, then add `tests/fixtures/rules/<ID>_bad.py` and `<ID>_good.py`.
207
+ The tests check that every rule fires on its bad file and stays silent on its good one.
208
+
209
+ Author: Subhabrat Biswal
@@ -0,0 +1,49 @@
1
+ # Add to your Azure DevOps repo as azure-pipelines.yml (or copy the steps into an existing pipeline),
2
+ # then add it as a build validation policy on the target branch so it runs on every pull request.
3
+ # Findings show in the "Scans" tab if the SARIF SAST Scans Tab extension is installed.
4
+ trigger:
5
+ branches:
6
+ include: [main]
7
+
8
+ pool:
9
+ vmImage: ubuntu-latest
10
+
11
+ steps:
12
+ - checkout: self
13
+ fetchDepth: 0 # needed for --diff
14
+
15
+ - task: UsePythonVersion@0
16
+ inputs:
17
+ versionSpec: "3.12"
18
+
19
+ - script: pip install sigreview
20
+ displayName: Install SigReview
21
+
22
+ - script: |
23
+ if [ -n "$SYSTEM_PULLREQUEST_TARGETBRANCH" ]; then
24
+ sigreview scan -f . --diff "origin/${SYSTEM_PULLREQUEST_TARGETBRANCH#refs/heads/}" --fail-on high
25
+ else
26
+ sigreview scan -f . --fail-on high
27
+ fi
28
+ displayName: SigReview
29
+
30
+ - script: |
31
+ mkdir -p "$(Build.ArtifactStagingDirectory)/CodeAnalysisLogs" "$(Build.ArtifactStagingDirectory)/report"
32
+ cp scan_result/sigreview_findings.sarif "$(Build.ArtifactStagingDirectory)/CodeAnalysisLogs/"
33
+ cp scan_result/sigreview_report.html scan_result/sigreview_findings.json scan_result/sigreview_summary.md "$(Build.ArtifactStagingDirectory)/report/"
34
+ displayName: Collect reports
35
+ condition: always()
36
+
37
+ - task: PublishBuildArtifacts@1
38
+ displayName: Publish SARIF (Scans tab)
39
+ condition: always()
40
+ inputs:
41
+ pathToPublish: $(Build.ArtifactStagingDirectory)/CodeAnalysisLogs
42
+ artifactName: CodeAnalysisLogs
43
+
44
+ - task: PublishBuildArtifacts@1
45
+ displayName: Publish HTML report
46
+ condition: always()
47
+ inputs:
48
+ pathToPublish: $(Build.ArtifactStagingDirectory)/report
49
+ artifactName: sigreview-report
@@ -0,0 +1,27 @@
1
+ # Copy to bitbucket-pipelines.yml in your project (or merge the step into yours).
2
+ image: python:3.12
3
+
4
+ pipelines:
5
+ pull-requests:
6
+ "**":
7
+ - step:
8
+ name: SigReview
9
+ script:
10
+ - pip install sigreview
11
+ - git fetch origin "$BITBUCKET_PR_DESTINATION_BRANCH"
12
+ - sigreview scan -f . --diff "origin/$BITBUCKET_PR_DESTINATION_BRANCH" --fail-on high
13
+ artifacts:
14
+ - scan_result/sigreview_report.html
15
+ - scan_result/sigreview_findings.json
16
+ - scan_result/sigreview_findings.sarif
17
+ - scan_result/sigreview_summary.md
18
+ branches:
19
+ main:
20
+ - step:
21
+ name: SigReview
22
+ script:
23
+ - pip install sigreview
24
+ - sigreview scan -f . --fail-on high
25
+ artifacts:
26
+ - scan_result/sigreview_report.html
27
+ - scan_result/sigreview_findings.json
@@ -0,0 +1,34 @@
1
+ # Copy to .github/workflows/sigreview.yml. Scans changed files on each pull request.
2
+ name: sigreview
3
+
4
+ on:
5
+ pull_request:
6
+ push:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+ security-events: write
12
+
13
+ jobs:
14
+ review:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ with:
19
+ fetch-depth: 0
20
+ - uses: actions/setup-python@v5
21
+ with:
22
+ python-version: "3.12"
23
+ - run: pip install sigreview
24
+ - run: sigreview scan -f . --fail-on high ${{ github.event_name == 'pull_request' && format('--diff origin/{0}', github.base_ref) || '' }}
25
+ - uses: github/codeql-action/upload-sarif@v3
26
+ if: always()
27
+ with:
28
+ sarif_file: scan_result/sigreview_findings.sarif
29
+ category: sigreview
30
+ - uses: actions/upload-artifact@v4
31
+ if: always()
32
+ with:
33
+ name: sigreview-report
34
+ path: scan_result/