|
| 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()) |
0 commit comments