generated from oracle/template-repo
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add instructions for writing new checks
Signed-off-by: behnazh-w <behnaz.hassanshahi@oracle.com>
- Loading branch information
Showing
4 changed files
with
204 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,6 @@ | ||
# Defining Checks | ||
|
||
The checks defined in this directory are automatically loaded during the startup of Macaron and used during the analysis. This `README.md` shows how a Check can be created. | ||
The checks defined in this directory are automatically loaded during the startup of Macaron and used during the analysis. For detailed instructions to write a new check, see our [website](https://oracle.github.io/macaron/pages/developers_guide/index.html). | ||
|
||
## Base Check | ||
The `BaseCheck` class (located at [base_check.py](./base_check.py)) is the abstract class to be inherited by other concrete checks. | ||
Please see [base_check.py](./base_check.py) for the attributes of a `BaseCheck` instance. | ||
|
||
## Writing a Macaron Check | ||
These are the steps for creating a Check in Macaron: | ||
1. Create a module with the name `<name>_check.py`. Note that Macaron **only** loads check modules that have this name format. | ||
2. Create a class that inherits `BaseCheck` and initiates the attributes of a `BaseCheck` instance. | ||
3. Register the newly created Check class to the Registry ([registry.py](../registry.py)). This will make the Check available to Macaron. For example: | ||
```python | ||
from macaron.slsa_analyzer.registry import registry | ||
|
||
# Check class is defined here | ||
# class ExampleCheck(BaseCheck): | ||
# ... | ||
|
||
registry.register(ExampleCheck()) | ||
``` | ||
4. Add an ORM mapped class for the check facts so that the policy engine can reason about the properties. To provide the mapped class, all you need to do is to add a class that inherits from `CheckFacts` class and add the following attributes (rename the `MyCheckFacts` check name and `__tablename__` as appropriate). | ||
|
||
```python | ||
class MyCheckFacts(CheckFacts): | ||
"""The ORM mapping for justifications in my check.""" | ||
|
||
__tablename__ = "_my_check" | ||
|
||
#: The primary key. | ||
id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003 | ||
|
||
#: The name of the column (property) that becomes available to policy engine. | ||
my_column_name: Mapped[str] = mapped_column(String, nullable=False) | ||
|
||
__mapper_args__ = { | ||
"polymorphic_identity": "_my_check", | ||
} | ||
``` | ||
|
||
For more examples, please see the existing Checks in [checks/](./). | ||
You can also have a look at the existing Checks in [this](./) directory for inspiration. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,41 @@ | ||
# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. | ||
# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved. | ||
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. | ||
|
||
"""This modules contains tests for the provenance available check.""" | ||
|
||
import os | ||
from pathlib import Path | ||
|
||
from macaron.database.table_definitions import Analysis, Component, Repository | ||
from macaron.slsa_analyzer.analyze_context import AnalyzeContext, ChecksOutputs | ||
from macaron.slsa_analyzer.checks.check_result import CheckResultType | ||
from macaron.slsa_analyzer.checks.vcs_check import VCSCheck | ||
from macaron.slsa_analyzer.git_service.base_git_service import NoneGitService | ||
from macaron.slsa_analyzer.slsa_req import SLSALevels | ||
from macaron.slsa_analyzer.specs.build_spec import BuildSpec | ||
from tests.conftest import MockAnalyzeContext | ||
|
||
from ...macaron_testcase import MacaronTestCase | ||
from ..mock_git_utils import initiate_repo | ||
|
||
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) | ||
REPO_DIR = os.path.join(BASE_DIR, "mock_repos", "vcs_check_repo/sample_repo") | ||
|
||
|
||
# pylint: disable=super-init-not-called | ||
class MockAnalyzeContext(AnalyzeContext): | ||
"""This class can be initiated without a git obj.""" | ||
|
||
def __init__(self) -> None: | ||
# Make the VCS Check fails. | ||
self.component = Component(purl="pkg:invalid/invalid", analysis=Analysis(), repository=None) | ||
self.ctx_data: dict = {} | ||
self.slsa_level = SLSALevels.LEVEL0 | ||
self.is_full_reach = False | ||
self.dynamic_data: ChecksOutputs = ChecksOutputs( | ||
git_service=NoneGitService(), | ||
build_spec=BuildSpec(tools=[]), | ||
ci_services=[], | ||
is_inferred_prov=True, | ||
expectation=None, | ||
package_registries=[], | ||
) | ||
self.wrapper_path = "" | ||
self.output_dir = "" | ||
|
||
|
||
class TestVCSCheck(MacaronTestCase): | ||
"""Test the vcs check.""" | ||
|
||
def test_vcs_check(self) -> None: | ||
"""Test the vcs check.""" | ||
check = VCSCheck() | ||
initiate_repo(REPO_DIR) | ||
|
||
component = Component( | ||
purl="pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", | ||
analysis=Analysis(), | ||
repository=Repository(complete_name="github.com/package-url/purl-spec"), | ||
) | ||
use_git_repo = AnalyzeContext(component=component, macaron_path=REPO_DIR, output_dir="") | ||
assert check.run_check(use_git_repo).result_type == CheckResultType.PASSED | ||
|
||
no_git_repo = MockAnalyzeContext() | ||
assert check.run_check(no_git_repo).result_type == CheckResultType.FAILED | ||
def test_vcs_check_valid_repo(macaron_path: Path) -> None: | ||
"""Test the vcs check for a valid repo.""" | ||
check = VCSCheck() | ||
initiate_repo(REPO_DIR) | ||
use_git_repo = MockAnalyzeContext(macaron_path=macaron_path, output_dir="") | ||
use_git_repo.component = Component( | ||
purl="pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", | ||
analysis=Analysis(), | ||
repository=Repository(complete_name="github.com/package-url/purl-spec"), | ||
) | ||
assert check.run_check(use_git_repo).result_type == CheckResultType.PASSED | ||
|
||
|
||
def test_vcs_check_invalid_repo(macaron_path: Path) -> None: | ||
"""Test the vcs check for an invalid repo.""" | ||
check = VCSCheck() | ||
initiate_repo(REPO_DIR) | ||
no_git_repo = MockAnalyzeContext(macaron_path=macaron_path, output_dir="") | ||
no_git_repo.component = Component( | ||
purl="pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", analysis=Analysis(), repository=None | ||
) | ||
assert check.run_check(no_git_repo).result_type == CheckResultType.FAILED |