Skip to content

Commit f39784a

Browse files
authored
feat: add a new check to report the build tool (#914)
This pull request adds a new check that identifies whether a supported build tool configuration exists in the associated source code repository of a software component. Signed-off-by: behnazh-w <[email protected]>
1 parent 7d3c63e commit f39784a

File tree

13 files changed

+167
-2
lines changed

13 files changed

+167
-2
lines changed

docs/source/index.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ the requirements that are currently supported by Macaron.
5353
* - Check ID
5454
- SLSA requirement
5555
- Concrete check
56+
* - ``mcn_build_tool_1``
57+
- **Build tool exists** - The source code repository includes configurations for a supported build tool used to produce the software component.
58+
- Detect the build tool used in the source code repository to build the software component.
5659
* - ``mcn_build_script_1``
5760
- **Scripted build** - All build steps were fully defined in a “build script”.
5861
- Identify and validate build script(s).
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Copyright (c) 2024 - 2024, 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 implementation of the build tool detection check."""
5+
6+
7+
import logging
8+
9+
from sqlalchemy import ForeignKey, String
10+
from sqlalchemy.orm import Mapped, mapped_column
11+
12+
from macaron.database.table_definitions import CheckFacts
13+
from macaron.slsa_analyzer.analyze_context import AnalyzeContext
14+
from macaron.slsa_analyzer.checks.base_check import BaseCheck, CheckResultType
15+
from macaron.slsa_analyzer.checks.check_result import CheckResultData, Confidence, JustificationType
16+
from macaron.slsa_analyzer.registry import registry
17+
from macaron.slsa_analyzer.slsa_req import ReqName
18+
19+
logger: logging.Logger = logging.getLogger(__name__)
20+
21+
22+
class BuildToolFacts(CheckFacts):
23+
"""The ORM mapping for the facts collected by the build tool check."""
24+
25+
__tablename__ = "_build_tool_check"
26+
27+
#: The primary key.
28+
id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
29+
30+
#: The build tool name.
31+
build_tool_name: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.TEXT})
32+
33+
#: The language of the artifact built by build tool.
34+
language: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.TEXT})
35+
36+
__mapper_args__ = {
37+
"polymorphic_identity": "_build_tool_check",
38+
}
39+
40+
41+
class BuildToolCheck(BaseCheck):
42+
"""This check detects the build tool used in the source code repository to build the software component."""
43+
44+
def __init__(self) -> None:
45+
"""Initialize instance."""
46+
check_id = "mcn_build_tool_1"
47+
description = "Detect the build tool used in the source code repository to build the software component."
48+
depends_on: list[tuple[str, CheckResultType]] = [("mcn_version_control_system_1", CheckResultType.PASSED)]
49+
eval_reqs = [ReqName.SCRIPTED_BUILD]
50+
super().__init__(check_id=check_id, description=description, depends_on=depends_on, eval_reqs=eval_reqs)
51+
52+
def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
53+
"""Implement the check in this method.
54+
55+
Parameters
56+
----------
57+
ctx : AnalyzeContext
58+
The object containing processed data for the target repo.
59+
60+
Returns
61+
-------
62+
CheckResultData
63+
The result of the check.
64+
"""
65+
if not ctx.component.repository:
66+
logger.info("Unable to find a Git repository for %s", ctx.component.purl)
67+
return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED)
68+
69+
build_tools = ctx.dynamic_data["build_spec"]["tools"]
70+
if not build_tools:
71+
return CheckResultData(result_tables=[], result_type=CheckResultType.FAILED)
72+
73+
result_tables: list[CheckFacts] = []
74+
for tool in build_tools:
75+
result_tables.append(
76+
BuildToolFacts(build_tool_name=tool.name, language=tool.language.value, confidence=Confidence.HIGH)
77+
)
78+
79+
return CheckResultData(
80+
result_tables=result_tables,
81+
result_type=CheckResultType.PASSED,
82+
)
83+
84+
85+
registry.register(BuildToolCheck())

src/macaron/slsa_analyzer/registry.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,10 @@ def _validate_check(check: Any) -> bool:
147147
True if check is valid, else False.
148148
"""
149149
if not isinstance(check, BaseCheck):
150+
class_name = check.__name__ if isinstance(check, type) else type(check).__name__
150151
logger.error(
151-
"The registered Check is of type %s. Please register a child class of BaseCheck.",
152-
type(check).__name__,
152+
"The registered Check %s is not a valid instance of BaseCheck.",
153+
class_name,
153154
)
154155
return False
155156

tests/integration/cases/facebook_yoga_yarn_classic/policy.dl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ Policy("test_policy", component_id, "") :-
88
check_passed(component_id, "mcn_build_script_1"),
99
check_passed(component_id, "mcn_build_service_1"),
1010
check_passed(component_id, "mcn_version_control_system_1"),
11+
check_passed(component_id, "mcn_build_tool_1"),
12+
build_tool_check(yarn_id, "yarn", "javascript"),
13+
check_facts(yarn_id, _, component_id,_,_),
1114
check_failed(component_id, "mcn_infer_artifact_pipeline_1"),
1215
check_failed(component_id, "mcn_provenance_available_1"),
1316
check_failed(component_id, "mcn_provenance_derived_commit_1"),

tests/integration/cases/google_guava/policy.dl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ Policy("test_policy", component_id, "") :-
1212
// the logic in the mcn_infer_artifact_pipeline_1 check.
1313
check_failed(component_id, "mcn_infer_artifact_pipeline_1"),
1414
check_passed(component_id, "mcn_version_control_system_1"),
15+
check_passed(component_id, "mcn_build_tool_1"),
16+
build_tool_check(maven_id, "maven", "java"),
17+
check_facts(maven_id, _, component_id,_,_),
1518
check_failed(component_id, "mcn_provenance_available_1"),
1619
check_failed(component_id, "mcn_provenance_derived_commit_1"),
1720
check_failed(component_id, "mcn_provenance_derived_repo_1"),

tests/integration/cases/jackson_databind_with_purl_and_no_deps/jackson-databind.dl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ Policy("test_policy", component_id, "") :-
88
check_passed(component_id, "mcn_build_script_1"),
99
check_passed(component_id, "mcn_build_service_1"),
1010
check_passed(component_id, "mcn_version_control_system_1"),
11+
check_passed(component_id, "mcn_build_tool_1"),
12+
build_tool_check(maven_id, "maven", "java"),
13+
check_facts(maven_id, _, component_id,_,_),
1114
check_failed(component_id, "mcn_infer_artifact_pipeline_1"),
1215
check_failed(component_id, "mcn_provenance_available_1"),
1316
check_failed(component_id, "mcn_provenance_derived_commit_1"),

tests/integration/cases/micronaut-projects_micronaut-test/micronaut-test.dl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Policy("test_policy", component_id, "") :-
1010
check_passed(component_id, "mcn_version_control_system_1"),
1111
check_passed(component_id, "mcn_provenance_available_1"),
1212
check_passed(component_id, "mcn_provenance_derived_repo_1"),
13+
check_passed(component_id, "mcn_build_tool_1"),
14+
build_tool_check(gradle_id, "gradle", "java"),
15+
check_facts(gradle_id, _, component_id,_,_),
1316
check_passed(component_id, "mcn_provenance_level_three_1"),
1417
check_failed(component_id, "mcn_infer_artifact_pipeline_1"),
1518
check_failed(component_id, "mcn_provenance_derived_commit_1"),

tests/integration/cases/slsa-framework_slsa-verifier/policy.dl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Policy("test_policy", component_id, "") :-
99
check_passed(component_id, "mcn_build_service_1"),
1010
check_passed(component_id, "mcn_trusted_builder_level_three_1"),
1111
check_passed(component_id, "mcn_version_control_system_1"),
12+
check_passed(component_id, "mcn_build_tool_1"),
13+
build_tool_check(go_id, "go", "go"),
14+
check_facts(go_id, _, component_id,_,_),
1215
check_passed(component_id, "mcn_provenance_available_1"),
1316
check_passed(component_id, "mcn_provenance_derived_commit_1"),
1417
check_passed(component_id, "mcn_provenance_derived_repo_1"),

tests/integration/cases/timyarkov_docker_test/policy.dl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ Policy("test_policy", component_id, "") :-
88
check_passed(component_id, "mcn_build_script_1"),
99
check_passed(component_id, "mcn_build_service_1"),
1010
check_passed(component_id, "mcn_version_control_system_1"),
11+
check_passed(component_id, "mcn_build_tool_1"),
12+
build_tool_check(docker_id, "docker", "docker"),
13+
check_facts(docker_id, _, component_id,_,_),
1114
check_failed(component_id, "mcn_infer_artifact_pipeline_1"),
1215
check_failed(component_id, "mcn_provenance_available_1"),
1316
check_failed(component_id, "mcn_provenance_derived_commit_1"),

tests/integration/cases/timyarkov_multibuild_test_maven/policy.dl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ Policy("test_policy", component_id, "") :-
88
check_passed(component_id, "mcn_build_script_1"),
99
check_passed(component_id, "mcn_build_service_1"),
1010
check_passed(component_id, "mcn_version_control_system_1"),
11+
check_passed(component_id, "mcn_build_tool_1"),
12+
build_tool_check(gradle_id, "gradle", "java"),
13+
check_facts(gradle_id, _, component_id,_,_),
14+
build_tool_check(maven_id, "maven", "java"),
15+
check_facts(maven_id, _, component_id,_,_),
1116
check_failed(component_id, "mcn_infer_artifact_pipeline_1"),
1217
check_failed(component_id, "mcn_provenance_available_1"),
1318
check_failed(component_id, "mcn_provenance_derived_commit_1"),

0 commit comments

Comments
 (0)