Skip to content
This repository was archived by the owner on Jul 28, 2023. It is now read-only.

Commit 96afb21

Browse files
committed
Contents for semgrep-precommit
1 parent 228a584 commit 96afb21

File tree

6 files changed

+807
-0
lines changed

6 files changed

+807
-0
lines changed

poetry.lock

Lines changed: 676 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[tool.poetry]
2+
name = "semgrep-precommit"
3+
version = "0.1.0"
4+
description = "Pre-commit hook for Semgrep with diff awareness"
5+
authors = ["Naveen S <dev@navs.page>"]
6+
readme = "README.md"
7+
packages = [{include = "semgrep_precommit"}]
8+
9+
[tool.poetry.dependencies]
10+
python = "^3.10"
11+
semgrep = "*"
12+
13+
[tool.poetry.scripts]
14+
semgrep-precommit = "semgrep_precommit.main:main"
15+
16+
[build-system]
17+
requires = ["poetry-core"]
18+
build-backend = "poetry.core.masonry.api"

semgrep_precommit/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "0.1.0"

semgrep_precommit/__main__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from semgrep_precommit.main import main
2+
3+
if __name__ == "__main__":
4+
raise main()

semgrep_precommit/main.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import os
2+
import subprocess
3+
import sys
4+
5+
from semgrep_precommit.utils import *
6+
7+
def run_semgrep(arguments: list[str]) -> int:
8+
"""run_semgrep runs semgrep with the given arguments.
9+
10+
Args:
11+
arguments (list[str]): A list of arguments to pass to semgrep.
12+
13+
Returns:
14+
int: The exit code of the semgrep command.
15+
"""
16+
command = ["semgrep", "scan"]
17+
command += arguments
18+
proc = subprocess.run(command)
19+
return proc.returncode
20+
21+
def main() -> None:
22+
"""main is the entrypoint for the pre-commit hook.
23+
"""
24+
arguments = list(sys.argv[1:])
25+
for argument in list(arguments):
26+
if is_file(argument):
27+
arguments.remove(argument)
28+
29+
current_commit, commit_before_current = None, None
30+
is_commit = commit_staged_files()
31+
if is_commit:
32+
current_commit, commit_before_current = get_last_two_commit_ids()
33+
os.environ["SEMGREP_BASELINE_REF"] = commit_before_current
34+
exit_code = run_semgrep(arguments)
35+
if is_commit:
36+
soft_reset_to_commit(commit_before_current)
37+
sys.exit(exit_code)
38+
39+
if __name__ == "__main__":
40+
raise main()

semgrep_precommit/utils.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import os
2+
import subprocess
3+
import typing
4+
5+
6+
def is_file(filename: str) -> bool:
7+
"""is_file checks if a given value is valid a file.
8+
9+
Args:
10+
filename (str): The filename to check.
11+
12+
Returns:
13+
bool: True if the file exists, False otherwise.
14+
"""
15+
if os.path.isfile(filename):
16+
return True
17+
return False
18+
19+
def commit_staged_files(message: str = "Dummy commit by semgrep pre-commit hook") -> bool:
20+
"""commit_staged_files commits all staged files with a given message.
21+
22+
Args:
23+
message (str, optional): A commit message.
24+
Defaults to "Dummy commit by semgrep pre-commit hook".
25+
26+
Returns:
27+
bool: True if the commit was successful, False otherwise.
28+
"""
29+
try:
30+
# We use -n to avoid running the pre-commit hook again
31+
subprocess.run(["git", "commit", "-n", "-m", message], stdout=subprocess.DEVNULL)
32+
except Exception:
33+
return False
34+
else:
35+
return True
36+
37+
def get_last_two_commit_ids() -> typing.Tuple[str | None, str | None]:
38+
"""get_last_two_commit_ids returns the last two commit IDs of the current branch
39+
40+
Returns:
41+
typing.Tuple[str | None, str | None]: The last two commit IDs
42+
"""
43+
commit_ids = None, None
44+
try:
45+
proc = subprocess.run(["git", "log", "--pretty=format:%H", "-n", "2"],
46+
capture_output=True)
47+
if proc.returncode == 0:
48+
commit_ids = proc.stdout.decode("utf-8").strip("\n").split("\n")
49+
except Exception:
50+
return None, None
51+
else:
52+
return tuple(commit_ids)
53+
54+
def soft_reset_to_commit(commit_id: str) -> bool:
55+
"""git_soft_reset_to_commit performs a soft reset to the previous commit
56+
57+
Args:
58+
commit_id (str): The commit ID to reset to
59+
60+
Returns:
61+
bool: True if the soft reset was successful, False otherwise
62+
"""
63+
try:
64+
subprocess.run(["git", "reset", "--soft", commit_id], stdout=subprocess.DEVNULL)
65+
except Exception:
66+
return False
67+
else:
68+
return True

0 commit comments

Comments
 (0)