Skip to content

Commit badf302

Browse files
committed
Add support for Bearer SAST
1 parent 4f047c8 commit badf302

8 files changed

Lines changed: 200 additions & 2 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Initializes the Bearer SAST integration module."""

codesectools/sasts/Bearer/cli.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Defines the command-line interface for the Bearer integration.
2+
3+
This script sets up the `typer` command group for Bearer and uses the
4+
`CLIFactory` to generate the standard set of subcommands (analyze, benchmark, etc.).
5+
"""
6+
7+
from codesectools.sasts.Bearer.sast import BearerSAST
8+
from codesectools.sasts.core.cli import CLIFactory
9+
10+
BearerCLIFactory = CLIFactory(BearerSAST(), custom_messages={"main": "Bearer SAST"})
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""Provide classes for parsing Bearer analysis results.
2+
3+
This module defines `BearerFinding` and `BearerAnalysisResult` to process
4+
the JSON output from a Bearer scan, converting it into the standardized
5+
format used by CodeSecTools.
6+
"""
7+
8+
import json
9+
from pathlib import Path
10+
from typing import Self
11+
12+
from codesectools.sasts.core.parser import AnalysisResult, Defect
13+
from codesectools.shared.cwe import CWEs
14+
from codesectools.utils import MissingFile
15+
16+
17+
class BearerFinding(Defect):
18+
"""Represent a single defect found by Bearer."""
19+
20+
def __init__(self, defect_data: dict, severity: str) -> None:
21+
"""Initialize a BearerFinding instance.
22+
23+
Args:
24+
defect_data: A dictionary representing a single finding from the JSON output.
25+
severity: The severity level of the finding.
26+
27+
"""
28+
super().__init__(
29+
file=Path(defect_data["filename"]).name,
30+
checker=defect_data["id"],
31+
category=severity,
32+
cwe=CWEs.from_id(int(defect_data["cwe_ids"][0])),
33+
data=defect_data,
34+
)
35+
36+
37+
class BearerAnalysisResult(AnalysisResult):
38+
"""Represent the complete result of a Bearer analysis."""
39+
40+
def __init__(self, output_dir: Path, result_data: dict, cmdout: dict) -> None:
41+
"""Initialize a BearerAnalysisResult instance.
42+
43+
Args:
44+
output_dir: The directory where the results are stored.
45+
result_data: Parsed data from the main Bearer JSON output.
46+
cmdout: A dictionary with metadata from the command execution.
47+
48+
"""
49+
super().__init__(
50+
name=output_dir.name,
51+
lang=cmdout["lang"],
52+
files=[],
53+
defects=[],
54+
time=cmdout["duration"],
55+
loc=cmdout["loc"],
56+
data=(result_data, cmdout),
57+
)
58+
59+
for severity, findings in result_data.items():
60+
for finding in findings:
61+
self.files.append(Path(finding["filename"]).name)
62+
self.defects.append(
63+
BearerFinding(defect_data=finding, severity=severity)
64+
)
65+
66+
@classmethod
67+
def load_from_output_dir(cls, output_dir: Path) -> Self:
68+
"""Load and parse Bearer analysis results from a directory.
69+
70+
Read `bearer_output.json` and `cstools_output.json` to construct a complete
71+
analysis result object.
72+
73+
Args:
74+
output_dir: The directory containing the Bearer output files.
75+
76+
Returns:
77+
An instance of `BearerAnalysisResult`.
78+
79+
Raises:
80+
MissingFile: If a required result file is not found.
81+
82+
"""
83+
# Cmdout
84+
cmdout = json.load((output_dir / "cstools_output.json").open())
85+
86+
# Analysis outputs
87+
analysis_output_path = output_dir / "bearer_output.json"
88+
if analysis_output_path.is_file():
89+
analysis_output = json.load(analysis_output_path.open("r"))
90+
else:
91+
raise MissingFile(["bearer_output.json"])
92+
93+
return cls(output_dir, analysis_output, cmdout)

codesectools/sasts/Bearer/sast.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""Define the SAST integration for Bearer.
2+
3+
This module provides the `BearerSAST` class, which configures and orchestrates
4+
the execution of Bearer scans using the core SAST framework.
5+
"""
6+
7+
from pathlib import Path
8+
9+
from codesectools.sasts.Bearer.parser import BearerAnalysisResult
10+
from codesectools.sasts.core.sast.properties import SASTProperties
11+
from codesectools.sasts.core.sast.requirements import (
12+
Binary,
13+
GitRepo,
14+
SASTRequirements,
15+
)
16+
from codesectools.sasts.core.sast.sast import SAST
17+
from codesectools.utils import USER_CACHE_DIR
18+
19+
20+
class BearerSAST(SAST):
21+
"""SAST integration for Bearer.
22+
23+
Attributes:
24+
name (str): The name of the SAST tool.
25+
supported_languages (list[str]): A list of supported programming languages.
26+
supported_dataset_names (list[str]): A list of names of compatible datasets.
27+
properties (SASTProperties): The properties of the SAST tool.
28+
requirements (SASTRequirements): The requirements for the SAST tool.
29+
commands (list[list[str]]): A list of command-line templates to be executed.
30+
output_files (list[tuple[Path, bool]]): A list of expected output files and
31+
whether they are required.
32+
parser (type[BearerAnalysisResult]): The parser class for the tool's results.
33+
color_mapping (dict): A mapping of result categories to colors for plotting.
34+
35+
"""
36+
37+
name = "Bearer"
38+
supported_languages = ["java"]
39+
supported_dataset_names = ["BenchmarkJava", "CVEfixes"]
40+
properties = SASTProperties(free=True, offline=True, buildless=True)
41+
requirements = SASTRequirements(
42+
full_reqs=[Binary("bearer", url="https://docs.bearer.com/quickstart/")],
43+
partial_reqs=[
44+
GitRepo(
45+
name="bearer-rules",
46+
repo_url="https://github.com/Bearer/bearer-rules.git",
47+
license="Elastic License 2.0",
48+
license_url="https://www.elastic.co/licensing/elastic-license",
49+
)
50+
],
51+
)
52+
commands = [
53+
[
54+
"bearer",
55+
"scan",
56+
".",
57+
"--force",
58+
"--disable-default-rules",
59+
f"--external-rule-dir={str(USER_CACHE_DIR / 'bearer-rules' / 'rules' / '{lang}')}",
60+
"--scanner=sast",
61+
"--format=json",
62+
"--output=bearer_output.json",
63+
"--disable-version-check",
64+
]
65+
]
66+
output_files = [
67+
(Path("bearer_output.json"), True),
68+
]
69+
parser = BearerAnalysisResult
70+
color_mapping = {
71+
"critical": "red",
72+
"high": "orangered",
73+
"medium": "orange",
74+
"low": "gold",
75+
"warning": "yellow",
76+
}

docs/sast/profiles/bearer.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: Bearer
2+
description: Bearer is a static application security testing (SAST) tool designed to scan your source code and analyze data flows to identify, filter, and prioritize security and privacy risks.
3+
type: Data Flow Analysis
4+
url: https://github.com/Bearer/bearer
5+
supported_version: 1.151.0
6+
legal:
7+
license: Elastic License 2.0
8+
license_type: Source Available
9+
license_url: https://www.elastic.co/licensing/elastic-license
10+
requirements:
11+
- An existing installation of Bearer.
12+
- An internet connection is required **only** to download [bearer-rules](https://github.com/Bearer/bearer-rules).
13+
extra: |
14+
!!! warning "Key Considerations"
15+
16+
The analysis tool is using Bearer Rules which is also license under [Elastic License 2.0](https://www.elastic.co/licensing/elastic-license).

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "CodeSecTools"
3-
version = "0.6.5"
3+
version = "0.7.0"
44
description = "A framework for code security that provides abstractions for static analysis tools and datasets to support their integration, testing, and evaluation."
55
readme = "README.md"
66
license = "AGPL-3.0-only"

tests/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ RUN apt update -qq && \
2020
apt install \
2121
git \
2222
cloc \
23+
curl \
2324
-y -qq --no-install-recommends && \
2425
rm -rf /var/lib/apt/lists/*
2526

2627
# Free SASTs only
2728
RUN pip install --no-cache semgrep
29+
RUN curl -sfL https://raw.githubusercontent.com/Bearer/bearer/main/contrib/install.sh | BINDIR=/usr/bin sh
2830

2931
COPY --from=builder --chown=app:app /app /app
3032
ENV PATH="/app/.venv/bin:$PATH"

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)