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.
- sigreview-1.0.0/.gitignore +14 -0
- sigreview-1.0.0/CHANGELOG.md +51 -0
- sigreview-1.0.0/LICENSE +21 -0
- sigreview-1.0.0/PKG-INFO +245 -0
- sigreview-1.0.0/README.md +209 -0
- sigreview-1.0.0/ci/azure-pipelines.yml +49 -0
- sigreview-1.0.0/ci/bitbucket-pipelines.yml +27 -0
- sigreview-1.0.0/ci/github-actions.yml +34 -0
- sigreview-1.0.0/ci/gitlab-ci.yml +23 -0
- sigreview-1.0.0/pyproject.toml +71 -0
- sigreview-1.0.0/src/sigreview/__init__.py +3 -0
- sigreview-1.0.0/src/sigreview/__main__.py +6 -0
- sigreview-1.0.0/src/sigreview/baseline.py +37 -0
- sigreview-1.0.0/src/sigreview/cli.py +324 -0
- sigreview-1.0.0/src/sigreview/config.py +51 -0
- sigreview-1.0.0/src/sigreview/diff.py +49 -0
- sigreview-1.0.0/src/sigreview/finding.py +53 -0
- sigreview-1.0.0/src/sigreview/loader.py +227 -0
- sigreview-1.0.0/src/sigreview/normalize.py +110 -0
- sigreview-1.0.0/src/sigreview/notebook.py +165 -0
- sigreview-1.0.0/src/sigreview/remote.py +268 -0
- sigreview-1.0.0/src/sigreview/report/__init__.py +31 -0
- sigreview-1.0.0/src/sigreview/report/console.py +47 -0
- sigreview-1.0.0/src/sigreview/report/html.py +117 -0
- sigreview-1.0.0/src/sigreview/report/json.py +50 -0
- sigreview-1.0.0/src/sigreview/report/markdown.py +54 -0
- sigreview-1.0.0/src/sigreview/report/sarif.py +87 -0
- sigreview-1.0.0/src/sigreview/report/templates/fonts/OFL.txt +93 -0
- sigreview-1.0.0/src/sigreview/report/templates/fonts/RedHatMono-Regular.woff2 +0 -0
- sigreview-1.0.0/src/sigreview/report/templates/fonts/RedHatText-Bold.woff2 +0 -0
- sigreview-1.0.0/src/sigreview/report/templates/fonts/RedHatText-Regular.woff2 +0 -0
- sigreview-1.0.0/src/sigreview/report/templates/report.html.j2 +310 -0
- sigreview-1.0.0/src/sigreview/rules/__init__.py +74 -0
- sigreview-1.0.0/src/sigreview/rules/base.py +66 -0
- sigreview-1.0.0/src/sigreview/rules/dataflow.py +359 -0
- sigreview-1.0.0/src/sigreview/rules/dataframe.py +552 -0
- sigreview-1.0.0/src/sigreview/rules/deep_learning.py +281 -0
- sigreview-1.0.0/src/sigreview/rules/evaluation.py +210 -0
- sigreview-1.0.0/src/sigreview/rules/genai.py +875 -0
- sigreview-1.0.0/src/sigreview/rules/helpers.py +439 -0
- sigreview-1.0.0/src/sigreview/rules/leakage.py +280 -0
- sigreview-1.0.0/src/sigreview/rules/ml.py +424 -0
- sigreview-1.0.0/src/sigreview/rules/notebook.py +294 -0
- sigreview-1.0.0/src/sigreview/rules/project.py +386 -0
- sigreview-1.0.0/src/sigreview/rules/spark.py +311 -0
- sigreview-1.0.0/src/sigreview/rules/timeseries.py +303 -0
- sigreview-1.0.0/src/sigreview/runners/__init__.py +45 -0
- sigreview-1.0.0/src/sigreview/runners/base.py +51 -0
- sigreview-1.0.0/src/sigreview/runners/deptry.py +100 -0
- sigreview-1.0.0/src/sigreview/runners/detect_secrets.py +150 -0
- sigreview-1.0.0/src/sigreview/runners/pip_audit.py +84 -0
- sigreview-1.0.0/src/sigreview/runners/pyrefly.py +50 -0
- sigreview-1.0.0/src/sigreview/runners/ruff.py +161 -0
- sigreview-1.0.0/src/sigreview/runners/vulture.py +86 -0
- sigreview-1.0.0/src/sigreview/scan.py +119 -0
- sigreview-1.0.0/src/sigreview/theme.py +53 -0
- sigreview-1.0.0/tests/conftest.py +38 -0
- sigreview-1.0.0/tests/fixtures/databricks_notebook.py +29 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB001_bad.ipynb +52 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB001_good.ipynb +74 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB002_bad.ipynb +34 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB002_good.ipynb +43 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB003_bad.ipynb +26 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB003_good.ipynb +26 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB004_bad.ipynb +32 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB004_good.ipynb +33 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB005_good.ipynb +25 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB006_bad.ipynb +36 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB006_good.ipynb +32 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB007_bad.ipynb +23 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB007_good.ipynb +22 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB008_bad.ipynb +21 -0
- sigreview-1.0.0/tests/fixtures/notebooks/NB008_good.ipynb +21 -0
- sigreview-1.0.0/tests/fixtures/rules/DF001_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/DF001_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DF002_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/DF002_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DF003_bad.py +2 -0
- sigreview-1.0.0/tests/fixtures/rules/DF003_good.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DF004_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/DF004_good.py +8 -0
- sigreview-1.0.0/tests/fixtures/rules/DF005_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DF005_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DF006_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/DF006_good.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/DF007_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DF007_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DF008_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DF008_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DF009_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/DF009_good.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/DF010_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DF010_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DF011_bad.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DF011_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/DF012_bad.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DF012_good.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DF013_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DF013_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DF014_bad.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DF014_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DL001_bad.py +14 -0
- sigreview-1.0.0/tests/fixtures/rules/DL001_good.py +14 -0
- sigreview-1.0.0/tests/fixtures/rules/DL002_bad.py +9 -0
- sigreview-1.0.0/tests/fixtures/rules/DL002_good.py +9 -0
- sigreview-1.0.0/tests/fixtures/rules/DL003_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DL003_good.py +9 -0
- sigreview-1.0.0/tests/fixtures/rules/DL004_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/DL004_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/DL005_bad.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DL005_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DL006_bad.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DL006_good.py +10 -0
- sigreview-1.0.0/tests/fixtures/rules/DL007_bad.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DL007_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DS001_bad.py +8 -0
- sigreview-1.0.0/tests/fixtures/rules/DS001_good.py +29 -0
- sigreview-1.0.0/tests/fixtures/rules/DS002_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DS002_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DS003_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DS003_good.py +8 -0
- sigreview-1.0.0/tests/fixtures/rules/DS004_bad.py +8 -0
- sigreview-1.0.0/tests/fixtures/rules/DS004_good.py +11 -0
- sigreview-1.0.0/tests/fixtures/rules/DS005_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/DS005_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/DS006_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DS006_good.py +8 -0
- sigreview-1.0.0/tests/fixtures/rules/DS007_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DS007_good.py +12 -0
- sigreview-1.0.0/tests/fixtures/rules/DS008_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DS008_good.py +9 -0
- sigreview-1.0.0/tests/fixtures/rules/DS009_bad.py +11 -0
- sigreview-1.0.0/tests/fixtures/rules/DS009_good.py +12 -0
- sigreview-1.0.0/tests/fixtures/rules/DS010_bad.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DS010_good.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/DS011_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DS011_good.py +10 -0
- sigreview-1.0.0/tests/fixtures/rules/DS012_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/DS012_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DS013_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/DS013_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/DS014_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DS014_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/DS015_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/DS015_good.py +8 -0
- sigreview-1.0.0/tests/fixtures/rules/EV001_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/EV001_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/EV002_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/EV002_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/EV003_bad.py +8 -0
- sigreview-1.0.0/tests/fixtures/rules/EV003_good.py +10 -0
- sigreview-1.0.0/tests/fixtures/rules/EV004_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/EV004_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM001_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM001_good.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM002_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM002_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM003_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM003_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM004_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM004_good.py +10 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM005_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM005_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM006_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM006_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM007_bad.py +2 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM007_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM008_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM008_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM009_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM009_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM010_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM010_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM011_bad.py +11 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM011_good.py +15 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM012_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM012_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM013_bad.py +2 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM013_good.py +2 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM015_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM015_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM016_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM016_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM017_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM017_good.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM018_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM018_good.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM019_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/LLM019_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/PR006_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/PR006_good.py +9 -0
- sigreview-1.0.0/tests/fixtures/rules/PR007_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/PR007_good.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/SP001_bad.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/SP001_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/SP002_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/SP002_good.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/SP003_bad.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/SP003_good.py +3 -0
- sigreview-1.0.0/tests/fixtures/rules/SP004_bad.py +9 -0
- sigreview-1.0.0/tests/fixtures/rules/SP004_good.py +10 -0
- sigreview-1.0.0/tests/fixtures/rules/SP005_bad.py +1 -0
- sigreview-1.0.0/tests/fixtures/rules/SP005_good.py +2 -0
- sigreview-1.0.0/tests/fixtures/rules/SP006_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/SP006_good.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/SP007_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/SP007_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/SP008_bad.py +1 -0
- sigreview-1.0.0/tests/fixtures/rules/SP008_good.py +2 -0
- sigreview-1.0.0/tests/fixtures/rules/TS001_bad.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/TS001_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/rules/TS002_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/TS002_good.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/TS003_bad.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/TS003_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/TS004_bad.py +8 -0
- sigreview-1.0.0/tests/fixtures/rules/TS004_good.py +8 -0
- sigreview-1.0.0/tests/fixtures/rules/TS005_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/TS005_good.py +5 -0
- sigreview-1.0.0/tests/fixtures/rules/TS006_bad.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/TS006_good.py +4 -0
- sigreview-1.0.0/tests/fixtures/rules/TS007_bad.py +6 -0
- sigreview-1.0.0/tests/fixtures/rules/TS007_good.py +7 -0
- sigreview-1.0.0/tests/fixtures/sample_project/.env +1 -0
- sigreview-1.0.0/tests/fixtures/sample_project/notebooks/explore.ipynb +69 -0
- sigreview-1.0.0/tests/fixtures/sample_project/requirements.txt +4 -0
- sigreview-1.0.0/tests/fixtures/sample_project/src/features.py +23 -0
- sigreview-1.0.0/tests/fixtures/sample_project/src/train.py +24 -0
- sigreview-1.0.0/tests/test_ci_files.py +17 -0
- sigreview-1.0.0/tests/test_cli.py +69 -0
- sigreview-1.0.0/tests/test_databricks.py +38 -0
- sigreview-1.0.0/tests/test_loader.py +44 -0
- sigreview-1.0.0/tests/test_normalize.py +72 -0
- sigreview-1.0.0/tests/test_pr_options.py +113 -0
- sigreview-1.0.0/tests/test_project_rules.py +97 -0
- sigreview-1.0.0/tests/test_remote.py +113 -0
- sigreview-1.0.0/tests/test_report.py +74 -0
- sigreview-1.0.0/tests/test_ruff_runner.py +45 -0
- sigreview-1.0.0/tests/test_rules.py +47 -0
|
@@ -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
|
sigreview-1.0.0/LICENSE
ADDED
|
@@ -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.
|
sigreview-1.0.0/PKG-INFO
ADDED
|
@@ -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/
|