Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8832c69
add security linter bandit to nox
Jannis-Mittenzwei Jun 20, 2024
8b307b9
bandit starting problem solved
Jannis-Mittenzwei Jun 21, 2024
5afccc2
change bandit options
Jannis-Mittenzwei Jun 26, 2024
bb62b2d
bandit report
Jannis-Mittenzwei Jul 3, 2024
8a01c78
Merge branch 'main' into feature#74-add-security-linter-to-the-toolbox
Jannis-Mittenzwei Jul 4, 2024
4ad9ac1
add security scoring
Jannis-Mittenzwei Jul 5, 2024
0f0dfeb
new bandit scoring + bandit rating
Jannis-Mittenzwei Jul 9, 2024
fdd11fa
typing List
Jannis-Mittenzwei Jul 9, 2024
75fa656
types corrected
Jannis-Mittenzwei Jul 9, 2024
283f368
added a test for bandit_scoring
Jannis-Mittenzwei Jul 11, 2024
ce0b1d0
run bandit test
Jannis-Mittenzwei Jul 11, 2024
9a9dff1
Update depdendency constraints (#214)
Nicoretti Jul 5, 2024
ad40034
add security linter bandit to nox
Jannis-Mittenzwei Jun 20, 2024
7d4c1eb
problems solved
Jannis-Mittenzwei Jul 16, 2024
700bcf5
Merge branch 'main' into feature#74-add-security-linter-to-the-toolbox
Jannis-Mittenzwei Jul 18, 2024
cc06d80
type check
Jannis-Mittenzwei Jul 19, 2024
bed13b0
new version of bandit rating and test
Jannis-Mittenzwei Jul 25, 2024
f19d66a
Merge branch 'main' into feature#74-add-security-linter-to-the-toolbox
Jannis-Mittenzwei Aug 13, 2024
4d9516d
function split up
Jannis-Mittenzwei Aug 13, 2024
3da401d
remove .security.json from git
Jannis-Mittenzwei Aug 13, 2024
d4cfe08
Merge branch 'main' into feature#74-add-security-linter-to-the-toolbox
Jannis-Mittenzwei Sep 10, 2024
706e6cf
Add security-check to Github jobs
Jannis-Mittenzwei Sep 10, 2024
acb07bd
Merge branch 'main' into feature#74-add-security-linter-to-the-toolbox
ckunki Sep 23, 2024
b28e378
Update exasol/toolbox/nox/_lint.py
ckunki Sep 23, 2024
ad7a8bd
Renamed security check to "security" in GitHub workflow, too
ckunki Sep 23, 2024
24c4900
Merge branch 'main' into feature#74-add-security-linter-to-the-toolbox
Jannis-Mittenzwei Sep 24, 2024
d2867bb
fix github workflow security-job
Jannis-Mittenzwei Sep 24, 2024
8337ad2
fix github workflow security-job
Jannis-Mittenzwei Sep 24, 2024
26b132a
add security file to github workflow report
Jannis-Mittenzwei Sep 24, 2024
5afd535
Update exasol/toolbox/nox/_lint.py
Nicoretti Sep 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,34 @@ jobs:
- name: Run type-check
run: poetry run nox -s type-check

security-job:
name: Security Checking (Python-${{ matrix.python-version }})
needs: [ version-check-job ]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ "3.8", "3.9", "3.10", "3.11" ]

steps:
- name: SCM Checkout
uses: actions/checkout@v4

- name: Setup Python & Poetry Environment
uses: ./.github/actions/python-environment
with:
python-version: ${{ matrix.python-version }}

- name: Run security
run: poetry run nox -s security

- name: Upload Artifacts
uses: actions/[email protected]
with:
name: security-python${{ matrix.python-version }}
path: .security.json
include-hidden-files: true

tests-job:
name: Tests (Python-${{ matrix.python-version }}, Exasol-${{ matrix.exasol-version}})
needs: [ build-documentation-job, lint-job, type-check-job ]
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
run: |
cp coverage-python3.9/.coverage ../
cp lint-python3.9/.lint.txt ../
cp security-python3.9/.security.json ../

- name: Generate Report
run: poetry run nox -s report -- -- --format json | tee metrics.json
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.lint.json
.lint.txt
.security.json

odbcconfig/odbcinst.ini

Expand Down
47 changes: 44 additions & 3 deletions exasol/toolbox/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
Any,
Callable,
Dict,
List,
Optional,
Union,
)
Expand Down Expand Up @@ -67,6 +68,26 @@ def from_score(score: float) -> "Rating":
"Uncategorized score, score should be in the following interval [0,10]."
)

@staticmethod
def bandit_rating(score: float) -> "Rating":
score = round(score, 3)
if score <= 0.2:
return Rating.F
elif 0.2 < score <= 1.6:
return Rating.E
elif 1.6 < score <= 3:
return Rating.D
elif 3 < score <= 4.4:
return Rating.C
elif 4.4 < score <= 5.8:
return Rating.B
elif 5.8 < score <= 6:
return Rating.A
else:
raise ValueError(
"Uncategorized score, score should be in the following interval [0,6]."
)


@dataclass(frozen=True)
class Report:
Expand Down Expand Up @@ -124,8 +145,27 @@ def reliability() -> Rating:
return Rating.NotAvailable


def security() -> Rating:
return Rating.NotAvailable
def security(file: Union[str, Path]) -> Rating:
with open(file) as json_file:
security_lint = json.load(json_file)
return Rating.bandit_rating(_bandit_scoring(security_lint["results"]))


def _bandit_scoring(ratings: List[Dict[str, Any]]) -> float:
def char(value: str, default: str = "H") -> str:
if value in ["HIGH", "MEDIUM", "LOW"]:
return value[0]
return default

weight = {"LL": 1/18, "LM": 1/15, "LH": 1/12, "ML": 1/9, "MM": 1/6, "MH": 1/3}
exp = 0.0
for infos in ratings:
severity = infos["issue_severity"]
if severity == "HIGH":
return 0.0
index = char(severity) + char(infos["issue_confidence"])
exp += weight[index]
return 6 * (2**-exp)


def technical_debt() -> Rating:
Expand All @@ -137,14 +177,15 @@ def create_report(
date: Optional[datetime.datetime] = None,
coverage_report: Union[str, Path] = ".coverage",
pylint_report: Union[str, Path] = ".lint.txt",
bandit_report: Union[str, Path] = ".security.json",
) -> Report:
return Report(
commit=commit,
date=date if date is not None else datetime.datetime.now(),
coverage=total_coverage(coverage_report),
maintainability=maintainability(pylint_report),
reliability=reliability(),
security=security(),
security=security(bandit_report),
technical_debt=technical_debt(),
)

Expand Down
34 changes: 34 additions & 0 deletions exasol/toolbox/nox/_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,33 @@ def _type_check(session: Session, files: Iterable[str]) -> None:
)


def _security_lint(session: Session, files: Iterable[str]) -> None:
session.run(
"poetry",
"run",
"bandit",
"--severity-level",
"low",
"--quiet",
"--format",
"json",
"--output",
".security.json",
"--exit-zero",
*files,
)
session.run(
"poetry",
"run",
"bandit",
"--severity-level",
"low",
"--quiet",
"--exit-zero",
*files,
)


@nox.session(python=False)
def lint(session: Session) -> None:
"""Runs the linter on the project"""
Expand All @@ -49,3 +76,10 @@ def type_check(session: Session) -> None:
"""Runs the type checker on the project"""
py_files = [f"{file}" for file in python_files(PROJECT_CONFIG.root)]
_type_check(session, py_files)


@nox.session(name="security", python=False)
def security_lint(session: Session) -> None:
"""Runs the security linter on the project"""
py_files = [f"{file}" for file in python_files(PROJECT_CONFIG.root)]
_security_lint(session, list(filter(lambda file: "test" not in file, py_files)))
3 changes: 2 additions & 1 deletion exasol/toolbox/nox/_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ def report(session: Session) -> None:
required_files = (
PROJECT_CONFIG.root / ".coverage",
PROJECT_CONFIG.root / ".lint.txt",
PROJECT_CONFIG.root / ".security.json",
)
if not all(file.exists() for file in required_files):
session.error(
"Please make sure you run the `coverage` and the `lint` target first"
"Please make sure you run the `coverage`, `security` and the `lint` target first"
)
sha1 = str(
session.run("git", "rev-parse", "HEAD", external=True, silent=True)
Expand Down
54 changes: 52 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ sphinx-design = ">=0.5.0,<1"
typer = {extras = ["all"], version = ">=0.7.0"}


bandit = {extras = ["toml"], version = "^1.7.9"}
[tool.poetry.group.dev.dependencies]
autoimport = "^1.4.0"

Expand Down
50 changes: 50 additions & 0 deletions test/unit/report_test.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from inspect import cleandoc
from typing import (
Dict,
List,
)

import pytest

from exasol.toolbox.metrics import (
Rating,
_bandit_scoring,
_static_code_analysis,
)

Expand Down Expand Up @@ -110,3 +115,48 @@ def test_static_code_analysis(
coverage_report = named_temp_file(name=".lint.txt", content=content)
actual = _static_code_analysis(coverage_report)
assert actual == expected


def _level(char):
levels = {"H": "HIGH", "M": "MEDIUM", "L": "LOW"}
return levels[char]


def _ratings(cases):
output = []
for rating in cases:
output.append(
{
"issue_severity": _level(rating[0]),
"issue_confidence": _level(rating[1]),
}
)
return output


@pytest.mark.parametrize(
"given,expected",
[
(["HH", "LL"], 0),
(["HM", "LM", "ML"], 0),
(["HL", "MH"], 0),
([], 6),
],
)
def test_bandit_value(given, expected):
assert _bandit_scoring(_ratings(given)) == expected


@pytest.mark.parametrize(
"lower,higher",
[
(["HL"], ["MH"]),
(["MH"], ["MM"]),
(["MM"], ["ML"]),
(["HL"], ["LL"]),
(["LL"], []),
(["MH", "LL"], ["MH"]),
],
)
def test_bandit_order(lower, higher):
assert _bandit_scoring(_ratings(lower)) < _bandit_scoring(_ratings(higher))