Skip to content

Commit 49d3401

Browse files
committed
feat: add checks to detect pip and poetry projects
Signed-off-by: sophie-bates <[email protected]>
1 parent 9a75df8 commit 49d3401

File tree

5 files changed

+225
-2
lines changed

5 files changed

+225
-2
lines changed

src/macaron/config/defaults.ini

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,19 @@ jenkins =
211211
gradle-git-publish
212212
gitPublishPush
213213

214+
# This is the spec for trusted Pip packaging tools.
215+
[builder.pip]
216+
entry_conf =
217+
setup.py
218+
setup.cfg
219+
pyproject.toml
220+
build_configs =
221+
222+
# This is the spec for trusted Poetry packaging tools.
223+
[builder.poetry]
224+
entry_conf = pyproject.toml
225+
build_configs = poetry.lock
226+
214227
# This is the spec for GitHub Actions CI.
215228
[ci.github_actions]
216229
entry_conf =
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
# Copyright (c) 2022 - 2022, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved.
22
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
33

44
"""The build_tool package contains the supported build tools for Macaron."""
55

66
from .base_build_tool import BaseBuildTool
77
from .gradle import Gradle
88
from .maven import Maven
9+
from .pip import Pip
10+
from .poetry import Poetry
911

1012
# The list of supported build tools. The order of the list determine the order
1113
# in which each build tool is checked against the target repository.
12-
BUILD_TOOLS: list[BaseBuildTool] = [Gradle(), Maven()]
14+
BUILD_TOOLS: list[BaseBuildTool] = [Gradle(), Maven(), Poetry(), Pip()]

src/macaron/slsa_analyzer/build_tool/base_build_tool.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,29 @@
1515
logger: logging.Logger = logging.getLogger(__name__)
1616

1717

18+
def find_files(path: str, file_name: str) -> list:
19+
"""Return a list of file paths that contain a certain file.
20+
21+
This method searches in the directory recursively.
22+
23+
Parameters
24+
----------
25+
path : str
26+
The path to search for the file.
27+
file_name : str
28+
The name of the file to search.
29+
30+
Returns
31+
-------
32+
list:
33+
The result list of strings or empty if the file doesn't exist anywhere lower than the path.
34+
"""
35+
pattern = os.path.join(path, "**", file_name)
36+
files_detected = glob.glob(pattern, recursive=True)
37+
38+
return files_detected
39+
40+
1841
def file_exists(path: str, file_name: str) -> bool:
1942
"""Return True if a file exists in a directory.
2043
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved.
2+
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
3+
4+
"""This module contains the Pip class which inherits BaseBuildTool.
5+
6+
This module is used to work with repositories that use Poetry for dependency management.
7+
"""
8+
9+
import logging
10+
11+
from macaron.config.defaults import defaults
12+
from macaron.dependency_analyzer import DependencyAnalyzer, NoneDependencyAnalyzer
13+
from macaron.slsa_analyzer.build_tool.base_build_tool import BaseBuildTool, file_exists
14+
15+
logger: logging.Logger = logging.getLogger(__name__)
16+
17+
18+
class Pip(BaseBuildTool):
19+
"""This class contains the information of the pip build tool."""
20+
21+
def __init__(self) -> None:
22+
"""Initialize instance."""
23+
super().__init__(name="pip")
24+
25+
def load_defaults(self) -> None:
26+
"""Load the default values from defaults.ini."""
27+
if "builder.pip" in defaults:
28+
for item in defaults["builder.pip"]:
29+
if hasattr(self, item):
30+
setattr(self, item, defaults.get_list("builder.pip", item))
31+
32+
def is_detected(self, repo_path: str) -> bool:
33+
"""Return True if this build tool is used in the target repo.
34+
35+
Parameters
36+
----------
37+
repo_path : str
38+
The path to the target repo.
39+
40+
Returns
41+
-------
42+
bool
43+
True if this build tool is detected, else False.
44+
"""
45+
for file in self.entry_conf:
46+
if file_exists(repo_path, file):
47+
return True
48+
return False
49+
50+
def prepare_config_files(self, wrapper_path: str, build_dir: str) -> bool:
51+
"""Prepare the necessary wrapper files for running the build.
52+
53+
This method will return False if there is any errors happened during operation.
54+
55+
Parameters
56+
----------
57+
wrapper_path : str
58+
The path where all necessary wrapper files are located.
59+
build_dir : str
60+
The path of the build dir. This is where all files are copied to.
61+
62+
Returns
63+
-------
64+
bool
65+
True if succeed else False.
66+
"""
67+
return True
68+
69+
def get_dep_analyzer(self, repo_path: str) -> DependencyAnalyzer:
70+
"""Create a DependencyAnalyzer for the build tool.
71+
72+
Parameters
73+
----------
74+
repo_path: str
75+
The path to the target repo.
76+
77+
Returns
78+
-------
79+
DependencyAnalyzer
80+
The DependencyAnalyzer object.
81+
"""
82+
return NoneDependencyAnalyzer()
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved.
2+
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
3+
4+
"""This module contains the Poetry class which inherits BaseBuildTool.
5+
6+
This module is used to work with repositories that use Poetry for dependency management.
7+
"""
8+
9+
import logging
10+
import tomllib
11+
12+
from macaron.config.defaults import defaults
13+
from macaron.dependency_analyzer import DependencyAnalyzer, NoneDependencyAnalyzer
14+
from macaron.slsa_analyzer.build_tool.base_build_tool import BaseBuildTool, file_exists, find_files
15+
16+
logger: logging.Logger = logging.getLogger(__name__)
17+
18+
19+
class Poetry(BaseBuildTool):
20+
"""This class contains the information of the poetry build tool."""
21+
22+
def __init__(self) -> None:
23+
"""Initialize instance."""
24+
super().__init__(name="poetry")
25+
26+
def load_defaults(self) -> None:
27+
"""Load the default values from defaults.ini."""
28+
if "builder.poetry" in defaults:
29+
for item in defaults["builder.poetry"]:
30+
if hasattr(self, item):
31+
setattr(self, item, defaults.get_list("builder.poetry", item))
32+
33+
def is_detected(self, repo_path: str) -> bool:
34+
"""Return True if this build tool is used in the target repo.
35+
36+
Parameters
37+
----------
38+
repo_path : str
39+
The path to the target repo.
40+
41+
Returns
42+
-------
43+
bool
44+
True if this build tool is detected, else False.
45+
"""
46+
for file in self.build_configs:
47+
if file_exists(repo_path, file):
48+
return True
49+
50+
for conf in self.entry_conf:
51+
# Find the paths of all pyproject.toml files.
52+
files_detected = find_files(repo_path, conf)
53+
54+
if files_detected:
55+
try:
56+
# Take the highest level file (shortest file path)
57+
file_path = min(files_detected, key=len)
58+
59+
# Parse the .toml file
60+
with open(file_path, "rb") as toml_file:
61+
data = tomllib.load(toml_file)
62+
if ("tool" in data) and ("poetry" in data["tool"]):
63+
return True
64+
return False
65+
except FileNotFoundError:
66+
logger.error("Failed to read the %s file.", conf)
67+
return False
68+
69+
return False
70+
71+
def prepare_config_files(self, wrapper_path: str, build_dir: str) -> bool:
72+
"""Prepare the necessary wrapper files for running the build.
73+
74+
This method will return False if there is any errors happened during operation.
75+
76+
Parameters
77+
----------
78+
wrapper_path : str
79+
The path where all necessary wrapper files are located.
80+
build_dir : str
81+
The path of the build dir. This is where all files are copied to.
82+
83+
Returns
84+
-------
85+
bool
86+
True if succeed else False.
87+
"""
88+
return False
89+
90+
def get_dep_analyzer(self, repo_path: str) -> DependencyAnalyzer:
91+
"""Create a DependencyAnalyzer for the build tool.
92+
93+
Parameters
94+
----------
95+
repo_path: str
96+
The path to the target repo.
97+
98+
Returns
99+
-------
100+
DependencyAnalyzer
101+
The DependencyAnalyzer object.
102+
"""
103+
return NoneDependencyAnalyzer()

0 commit comments

Comments
 (0)