diff --git a/scripts/dev_scripts/integration_tests.sh b/scripts/dev_scripts/integration_tests.sh index d348f9fb9..fdeaac879 100755 --- a/scripts/dev_scripts/integration_tests.sh +++ b/scripts/dev_scripts/integration_tests.sh @@ -100,6 +100,56 @@ $RUN_MACARON analyze -rp https://github.com/timyarkov/docker_test -b main -d 404 python $COMPARE_JSON_OUT $JSON_RESULT $JSON_EXPECTED || log_fail +echo -e "\n----------------------------------------------------------------------------------" +echo "uiv-lib/uiv: Analysing the repo path, the branch name and the commit digest for an npm project," +echo "skipping dependency resolution." +echo -e "----------------------------------------------------------------------------------\n" +JSON_EXPECTED=$WORKSPACE/tests/e2e/expected_results/uiv/uiv.json +JSON_RESULT=$WORKSPACE/output/reports/github_com/uiv-lib/uiv/uiv.json +$RUN_MACARON analyze -rp https://github.com/uiv-lib/uiv -b dev -d 057b25b4db0913edab4cf728c306085e6fc20d49 --skip-deps || log_fail + +python $COMPARE_JSON_OUT $JSON_RESULT $JSON_EXPECTED || log_fail + +echo -e "\n----------------------------------------------------------------------------------" +echo "onu-ui/onu-ui: Analysing the repo path, the branch name and the commit digest for a pnpm project," +echo "skipping dependency resolution." +echo -e "----------------------------------------------------------------------------------\n" +JSON_EXPECTED=$WORKSPACE/tests/e2e/expected_results/onu-ui/onu-ui.json +JSON_RESULT=$WORKSPACE/output/reports/github_com/onu-ui/onu-ui/onu-ui.json +$RUN_MACARON analyze -rp https://github.com/onu-ui/onu-ui -b main -d e3f2825c3940002a920d65476116a64684b3d95e --skip-deps || log_fail + +python $COMPARE_JSON_OUT $JSON_RESULT $JSON_EXPECTED || log_fail + +echo -e "\n----------------------------------------------------------------------------------" +echo "facebook/yoga: Analysing the repo path, the branch name and the commit digest for a Yarn classic" +echo "project, skipping dependency resolution." +echo -e "----------------------------------------------------------------------------------\n" +JSON_EXPECTED=$WORKSPACE/tests/e2e/expected_results/yoga/yoga.json +JSON_RESULT=$WORKSPACE/output/reports/github_com/facebook/yoga/yoga.json +$RUN_MACARON analyze -rp https://github.com/facebook/yoga -b main -d f8e2bc0875c145c429d0e865c9b83a40f65b3070 --skip-deps || log_fail + +python $COMPARE_JSON_OUT $JSON_RESULT $JSON_EXPECTED || log_fail + +echo -e "\n----------------------------------------------------------------------------------" +echo "wojtekmaj/react-pdf: Analysing the repo path, the branch name and the commit digest for a Yarn modern" +echo "project, skipping dependency resolution." +echo -e "----------------------------------------------------------------------------------\n" +JSON_EXPECTED=$WORKSPACE/tests/e2e/expected_results/react-pdf/react-pdf.json +JSON_RESULT=$WORKSPACE/output/reports/github_com/wojtekmaj/react-pdf/react-pdf.json +$RUN_MACARON analyze -rp https://github.com/wojtekmaj/react-pdf -b main -d be18436b7be827eb993b2e1e4bd9230dd835a9a3 --skip-deps || log_fail + +python $COMPARE_JSON_OUT $JSON_RESULT $JSON_EXPECTED || log_fail + +echo -e "\n----------------------------------------------------------------------------------" +echo "sigstore/sget: Analysing the repo path, the branch name and the" +echo "commit digest for a Go project, skipping dependency resolution." +echo -e "----------------------------------------------------------------------------------\n" +JSON_EXPECTED=$WORKSPACE/tests/e2e/expected_results/sget/sget.json +JSON_RESULT=$WORKSPACE/output/reports/github_com/sigstore/sget/sget.json +$RUN_MACARON analyze -rp https://github.com/sigstore/sget -b main -d 99e7b91204d391ccc76507f7079b6d2a7957489e --skip-deps || log_fail + +python $COMPARE_JSON_OUT $JSON_RESULT $JSON_EXPECTED || log_fail + echo -e "\n----------------------------------------------------------------------------------" echo "apache/maven: Analyzing with PURL and repository path without dependency resolution." echo -e "----------------------------------------------------------------------------------\n" diff --git a/src/macaron/config/defaults.ini b/src/macaron/config/defaults.ini index abca6969e..0858ede56 100644 --- a/src/macaron/config/defaults.ini +++ b/src/macaron/config/defaults.ini @@ -318,6 +318,71 @@ deploy_arg = github_actions = docker/build-push-action +# This is the spec for trusted NPM build tool usages. +# This also includes the spec for pnpm, since for the purposes of this program +# they work more or less the same. +[builder.npm] +entry_conf = + .npmrc +build_configs = + package.json +package_lock = + package-lock.json + pnpm-lock.yaml +builder = + npm + pnpm +# Build args not defined since npm build is just a plumbing command https://docs.npmjs.com/cli/v6/commands/npm-build +# and SLSA v1.0 removes the scripted build requirement https://slsa.dev/spec/v1.0/requirements +build_arg = +deploy_arg = + publish +[builder.npm.ci.deploy] +github_actions = + JS-DevTools/npm-publish + +# This is the spec for trusted Yarn build tool usages. +# The entries need to cover both Yarn classic and Yarn modern; namely .yarnrc vs .yarnrc.yml +# for the entry configs, publish vs npm publish for the deploy args, and yarn.lock for +# Yarn classic's package lock. +# See https://yarnpkg.com/migration/guide and https://classic.yarnpkg.com/lang/en/docs/yarn-lock/ +# Currently npm publish is not supported here due to the multiple arguments; see issue #493. +[builder.yarn] +entry_conf = + .yarnrc + .yarnrc.yml +build_configs = + package.json +package_lock = + package-lock.json + yarn.lock +builder = + yarn +# Build args not defined for similar reasons to npm +build_arg = +deploy_arg = + publish + +# This is the spec for trusted Go build tool usages. +[builder.go] +entry_conf = +build_configs = + go.mod + go.sum +builder = + go +build_arg = + build + install +# Goreleaser will be taken as publisher as per https://github.com/oracle/macaron/milestone/14 +publisher = + goreleaser +deploy_arg = + release +[builder.go.ci.deploy] +github_actions = + goreleaser/goreleaser-action + # This is the spec for GitHub Actions CI. [ci.github_actions] entry_conf = diff --git a/src/macaron/slsa_analyzer/build_tool/__init__.py b/src/macaron/slsa_analyzer/build_tool/__init__.py index b9a45e500..4638e1e5d 100644 --- a/src/macaron/slsa_analyzer/build_tool/__init__.py +++ b/src/macaron/slsa_analyzer/build_tool/__init__.py @@ -5,11 +5,14 @@ from .base_build_tool import BaseBuildTool from .docker import Docker +from .go import Go from .gradle import Gradle from .maven import Maven +from .npm import NPM from .pip import Pip from .poetry import Poetry +from .yarn import Yarn # The list of supported build tools. The order of the list determine the order # in which each build tool is checked against the target repository. -BUILD_TOOLS: list[BaseBuildTool] = [Gradle(), Maven(), Poetry(), Pip(), Docker()] +BUILD_TOOLS: list[BaseBuildTool] = [Gradle(), Maven(), Poetry(), Pip(), Docker(), NPM(), Yarn(), Go()] diff --git a/src/macaron/slsa_analyzer/build_tool/go.py b/src/macaron/slsa_analyzer/build_tool/go.py new file mode 100644 index 000000000..6faef14e0 --- /dev/null +++ b/src/macaron/slsa_analyzer/build_tool/go.py @@ -0,0 +1,85 @@ +# Copyright (c) 2023 - 2023, 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 module contains the Go class which inherits BaseBuildTool. + +This module is used to work with repositories that have Go. +""" + +from macaron.config.defaults import defaults +from macaron.dependency_analyzer.dependency_resolver import DependencyAnalyzer, NoneDependencyAnalyzer +from macaron.slsa_analyzer.build_tool.base_build_tool import BaseBuildTool, file_exists + + +class Go(BaseBuildTool): + """This class contains the information of the Go build tool.""" + + def __init__(self) -> None: + super().__init__(name="go") + + def load_defaults(self) -> None: + """Load the default values from defaults.ini.""" + if "builder.go" in defaults: + for item in defaults["builder.go"]: + if hasattr(self, item): + setattr(self, item, defaults.get_list("builder.go", item)) + + if "builder.go.ci.deploy" in defaults: + for item in defaults["builder.go.ci.deploy"]: + if item in self.ci_deploy_kws: + self.ci_deploy_kws[item] = defaults.get_list("builder.go.ci.deploy", item) + + def is_detected(self, repo_path: str) -> bool: + """Return True if this build tool is used in the target repo. + + Parameters + ---------- + repo_path : str + The path to the target repo. + + Returns + ------- + bool + True if this build tool is detected, else False. + """ + go_config_files = self.build_configs + self.entry_conf + for file in go_config_files: + if file_exists(repo_path, file): + return True + + return False + + def prepare_config_files(self, wrapper_path: str, build_dir: str) -> bool: + """Prepare the necessary wrapper files for running the build. + + Go doesn't require preparation, so return true. + + Parameters + ---------- + wrapper_path : str + The path where all necessary wrapper files are located. + build_dir : str + The path of the build dir. This is where all files are copied to. + + Returns + ------- + bool + True if succeed else False. + """ + return True + + def get_dep_analyzer(self, repo_path: str) -> DependencyAnalyzer: + """Create a DependencyAnalyzer for the build tool. + + Parameters + ---------- + repo_path: str + The path to the target repo. + + Returns + ------- + DependencyAnalyzer + The DependencyAnalyzer object. + """ + # TODO: Implement this method. + return NoneDependencyAnalyzer() diff --git a/src/macaron/slsa_analyzer/build_tool/npm.py b/src/macaron/slsa_analyzer/build_tool/npm.py new file mode 100644 index 000000000..169404af1 --- /dev/null +++ b/src/macaron/slsa_analyzer/build_tool/npm.py @@ -0,0 +1,89 @@ +# Copyright (c) 2023 - 2023, 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 module contains the NPM class which inherits BaseBuildTool. + +This module is used to work with repositories that use npm/pnpm as its +build tool. +""" + +from macaron.config.defaults import defaults +from macaron.dependency_analyzer.dependency_resolver import DependencyAnalyzer, NoneDependencyAnalyzer +from macaron.slsa_analyzer.build_tool.base_build_tool import BaseBuildTool, file_exists + + +class NPM(BaseBuildTool): + """This class contains the information of the npm/pnpm build tool.""" + + def __init__(self) -> None: + super().__init__(name="npm") + + def load_defaults(self) -> None: + """Load the default values from defaults.ini.""" + if "builder.npm" in defaults: + for item in defaults["builder.npm"]: + if hasattr(self, item): + setattr(self, item, defaults.get_list("builder.npm", item)) + + if "builder.npm.ci.deploy" in defaults: + for item in defaults["builder.npm.ci.deploy"]: + if item in self.ci_deploy_kws: + self.ci_deploy_kws[item] = defaults.get_list("builder.npm.ci.deploy", item) + + def is_detected(self, repo_path: str) -> bool: + """Return True if this build tool is used in the target repo. + + Parameters + ---------- + repo_path : str + The path to the target repo. + + Returns + ------- + bool + True if this build tool is detected, else False. + """ + # TODO: When more complex build detection is being implemented, consider + # cases like .npmrc existing but not package-lock.json and whether + # they would still count as "detected" + npm_config_files = self.build_configs + self.package_lock + self.entry_conf + for file in npm_config_files: + if file_exists(repo_path, file): + return True + + return False + + def prepare_config_files(self, wrapper_path: str, build_dir: str) -> bool: + """Prepare the necessary wrapper files for running the build. + + npm/pnpm doesn't require preparation, so return true. + + Parameters + ---------- + wrapper_path : str + The path where all necessary wrapper files are located. + build_dir : str + The path of the build dir. This is where all files are copied to. + + Returns + ------- + bool + True if succeed else False. + """ + return True + + def get_dep_analyzer(self, repo_path: str) -> DependencyAnalyzer: + """Create a DependencyAnalyzer for the build tool. + + Parameters + ---------- + repo_path: str + The path to the target repo. + + Returns + ------- + DependencyAnalyzer + The DependencyAnalyzer object. + """ + # TODO: Implement this method. + return NoneDependencyAnalyzer() diff --git a/src/macaron/slsa_analyzer/build_tool/yarn.py b/src/macaron/slsa_analyzer/build_tool/yarn.py new file mode 100644 index 000000000..0076561e3 --- /dev/null +++ b/src/macaron/slsa_analyzer/build_tool/yarn.py @@ -0,0 +1,90 @@ +# Copyright (c) 2023 - 2023, 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 module contains the Yarn class which inherits BaseBuildTool. + +This module is used to work with repositories that use Yarn as its +build tool. +""" + +from macaron.config.defaults import defaults +from macaron.dependency_analyzer.dependency_resolver import DependencyAnalyzer, NoneDependencyAnalyzer +from macaron.slsa_analyzer.build_tool.base_build_tool import BaseBuildTool, file_exists + + +class Yarn(BaseBuildTool): + """This class contains the information of the yarn build tool.""" + + def __init__(self) -> None: + super().__init__(name="yarn") + + def load_defaults(self) -> None: + """Load the default values from defaults.ini.""" + if "builder.yarn" in defaults: + for item in defaults["builder.yarn"]: + if hasattr(self, item): + setattr(self, item, defaults.get_list("builder.yarn", item)) + + # TODO: Find a suitable github action for Yarn + # if "builder.yarn.ci.deploy" in defaults: + # for item in defaults["builder.yarn.ci.deploy"]: + # if item in self.ci_deploy_kws: + # self.ci_deploy_kws[item] = defaults.get_list("builder.yarn.ci.deploy", item) + + def is_detected(self, repo_path: str) -> bool: + """Return True if this build tool is used in the target repo. + + Parameters + ---------- + repo_path : str + The path to the target repo. + + Returns + ------- + bool + True if this build tool is detected, else False. + """ + # TODO: When more complex build detection is being implemented, consider + # cases like .yarnrc existing but not package-lock.json and whether + # they would still count as "detected" + yarn_config_files = self.build_configs + self.package_lock + self.entry_conf + for file in yarn_config_files: + if file_exists(repo_path, file): + return True + + return False + + def prepare_config_files(self, wrapper_path: str, build_dir: str) -> bool: + """Prepare the necessary wrapper files for running the build. + + yarn doesn't require preparation, so return true. + + Parameters + ---------- + wrapper_path : str + The path where all necessary wrapper files are located. + build_dir : str + The path of the build dir. This is where all files are copied to. + + Returns + ------- + bool + True if succeed else False. + """ + return True + + def get_dep_analyzer(self, repo_path: str) -> DependencyAnalyzer: + """Create a DependencyAnalyzer for the build tool. + + Parameters + ---------- + repo_path: str + The path to the target repo. + + Returns + ------- + DependencyAnalyzer + The DependencyAnalyzer object. + """ + # TODO: Implement this method. + return NoneDependencyAnalyzer() diff --git a/src/macaron/slsa_analyzer/checks/build_as_code_check.py b/src/macaron/slsa_analyzer/checks/build_as_code_check.py index 959c9974e..c85f4ee78 100644 --- a/src/macaron/slsa_analyzer/checks/build_as_code_check.py +++ b/src/macaron/slsa_analyzer/checks/build_as_code_check.py @@ -116,6 +116,7 @@ def _has_deploy_command(self, commands: list[list[str]], build_tool: BaseBuildTo if check_build_commands or check_module_build_commands: # Check the arguments in the bash command for the deploy goals. # If there are no deploy args for this build tool, accept as deploy command. + # TODO: Support multi-argument build keywords, issue #493. if not build_tool.deploy_arg: logger.info("No deploy arguments required. Accept %s as deploy command.", str(com)) return str(com) diff --git a/src/macaron/slsa_analyzer/checks/build_service_check.py b/src/macaron/slsa_analyzer/checks/build_service_check.py index 37cb4ed6c..7cbba59bc 100644 --- a/src/macaron/slsa_analyzer/checks/build_service_check.py +++ b/src/macaron/slsa_analyzer/checks/build_service_check.py @@ -107,6 +107,7 @@ def _has_build_command(self, commands: list[list[str]], build_tool: BaseBuildToo if check_build_commands or check_module_build_commands: # Check the arguments in the bash command for the build goals. # If there are no build args for this build tool, accept as build command. + # TODO: Support multi-argument build keywords, issue #493. if not build_tool.build_arg: logger.info("No build arguments required. Accept %s as build command.", str(com)) return str(com) diff --git a/tests/conftest.py b/tests/conftest.py index fdf247cd4..82193fc14 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,10 +11,13 @@ from macaron.database.table_definitions import Analysis, Component, Repository from macaron.slsa_analyzer.analyze_context import AnalyzeContext from macaron.slsa_analyzer.build_tool.docker import Docker +from macaron.slsa_analyzer.build_tool.go import Go from macaron.slsa_analyzer.build_tool.gradle import Gradle from macaron.slsa_analyzer.build_tool.maven import Maven +from macaron.slsa_analyzer.build_tool.npm import NPM from macaron.slsa_analyzer.build_tool.pip import Pip from macaron.slsa_analyzer.build_tool.poetry import Poetry +from macaron.slsa_analyzer.build_tool.yarn import Yarn from macaron.slsa_analyzer.ci_service.circleci import CircleCI from macaron.slsa_analyzer.ci_service.github_actions import GitHubActions from macaron.slsa_analyzer.ci_service.gitlab_ci import GitLabCI @@ -168,6 +171,63 @@ def docker_tool(setup_test) -> Docker: # type: ignore # pylint: disable=unused- return docker +@pytest.fixture(autouse=True) +def npm_tool(setup_test) -> NPM: # type: ignore # pylint: disable=unused-argument + """Create a NPM tool instance. + + Parameters + ---------- + setup_test + Depends on setup_test fixture. + + Returns + ------- + NPM + The NPM instance. + """ + npm = NPM() + npm.load_defaults() + return npm + + +@pytest.fixture(autouse=True) +def yarn_tool(setup_test) -> Yarn: # type: ignore # pylint: disable=unused-argument + """Create a Yarn tool instance. + + Parameters + ---------- + setup_test + Depends on setup_test fixture. + + Returns + ------- + Yarn + The Yarn instance. + """ + yarn = Yarn() + yarn.load_defaults() + return yarn + + +@pytest.fixture(autouse=True) +def go_tool(setup_test) -> Go: # type: ignore # pylint: disable=unused-argument + """Create a Go tool instance. + + Parameters + ---------- + setup_test + Depends on setup_test fixture. + + Returns + ------- + Go + The Go instance. + """ + go = Go() # pylint: disable=invalid-name + go.load_defaults() + return go + + class MockGitHubActions(GitHubActions): """Mock the GitHubActions class.""" diff --git a/tests/e2e/expected_results/onu-ui/onu-ui.json b/tests/e2e/expected_results/onu-ui/onu-ui.json new file mode 100644 index 000000000..b79e46b50 --- /dev/null +++ b/tests/e2e/expected_results/onu-ui/onu-ui.json @@ -0,0 +1,253 @@ +{ + "metadata": { + "timestamps": "2023-09-30 15:56:04" + }, + "target": { + "info": { + "full_name": "pkg:github.com/onu-ui/onu-ui@e3f2825c3940002a920d65476116a64684b3d95e", + "local_cloned_path": "git_repos/github_com/onu-ui/onu-ui", + "remote_path": "https://github.com/onu-ui/onu-ui", + "branch": "main", + "commit_hash": "e3f2825c3940002a920d65476116a64684b3d95e", + "commit_date": "2023-09-29T19:41:13+08:00" + }, + "provenances": { + "is_inferred": true, + "content": { + "github_actions": [ + { + "_type": "https://in-toto.io/Statement/v0.1", + "subject": [], + "predicateType": "https://slsa.dev/provenance/v0.2", + "predicate": { + "builder": { + "id": "https://github.com/onu-ui/onu-ui/blob/e3f2825c3940002a920d65476116a64684b3d95e/.github/workflows/release.yml" + }, + "buildType": "Custom github_actions", + "invocation": { + "configSource": { + "uri": "https://github.com/onu-ui/onu-ui@refs/heads/main", + "digest": { + "sha1": "e3f2825c3940002a920d65476116a64684b3d95e" + }, + "entryPoint": "https://github.com/onu-ui/onu-ui/blob/e3f2825c3940002a920d65476116a64684b3d95e/.github/workflows/release.yml" + }, + "parameters": {}, + "environment": {} + }, + "buildConfig": { + "jobID": "release", + "stepID": "Publish to npm" + }, + "metadata": { + "buildInvocationId": "", + "buildStartedOn": "", + "buildFinishedOn": "", + "completeness": { + "parameters": "false", + "environment": "false", + "materials": "false" + }, + "reproducible": "false" + }, + "materials": [ + { + "uri": "", + "digest": {} + } + ] + } + } + ] + } + }, + "checks": { + "summary": { + "DISABLED": 0, + "FAILED": 6, + "PASSED": 4, + "SKIPPED": 0, + "UNKNOWN": 0 + }, + "results": [ + { + "check_id": "mcn_build_as_code_1", + "check_description": "The build definition and configuration executed by the build service is verifiably derived from text file definitions stored in a version control system.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + { + "The target repository uses build tool npm to deploy": "https://github.com/onu-ui/onu-ui/blob/e3f2825c3940002a920d65476116a64684b3d95e/.github/workflows/release.yml", + "The build is triggered by": "https://github.com/onu-ui/onu-ui/blob/e3f2825c3940002a920d65476116a64684b3d95e/.github/workflows/release.yml" + }, + "Deploy command: ['pnpm', '-r', 'publish', '--access', 'public', '--no-git-checks']", + "However, could not find a passing workflow run.", + "The target repository does not use yarn to deploy." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_script_1", + "check_description": "Check if the target repo has a valid build script.", + "slsa_requirements": [ + "Scripted Build - SLSA Level 1" + ], + "justification": [ + "Check mcn_build_script_1 is set to PASSED because mcn_build_service_1 PASSED." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_service_1", + "check_description": "Check if the target repo has a valid build service.", + "slsa_requirements": [ + "Build service - SLSA Level 2" + ], + "justification": [ + "Check mcn_build_service_1 is set to PASSED because mcn_build_as_code_1 PASSED." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_version_control_system_1", + "check_description": "Check whether the target repo uses a version control system.", + "slsa_requirements": [ + "Version controlled - SLSA Level 2" + ], + "justification": [ + { + "This is a Git repository": "https://github.com/onu-ui/onu-ui" + } + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_infer_artifact_pipeline_1", + "check_description": "Detects potential pipelines from which an artifact is published.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + "Unable to find a publishing timestamp for the artifact." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_available_1", + "check_description": "Check whether the target has intoto provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Could not find any SLSA or Witness provenances." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_expectation_1", + "check_description": "Check whether the SLSA provenance for the produced artifact conforms to the expected value.", + "slsa_requirements": [ + "Provenance conforms with expectations - SLSA Level 3" + ], + "justification": [ + "Check mcn_provenance_expectation_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_level_three_1", + "check_description": "Check whether the target has SLSA provenance level 3.", + "slsa_requirements": [ + "Provenance - Non falsifiable - SLSA Level 3", + "Provenance content - Includes all build parameters - SLSA Level 3", + "Provenance content - Identifies entry point - SLSA Level 3", + "Provenance content - Identifies source code - SLSA Level 2" + ], + "justification": [ + "Check mcn_provenance_level_three_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "check_description": "Check whether the target has a level-1 witness provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Check mcn_provenance_witness_level_one_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "check_description": "Check whether the target uses a trusted SLSA level 3 builder.", + "slsa_requirements": [ + "Hermetic - SLSA Level 4", + "Isolated - SLSA Level 3", + "Parameterless - SLSA Level 4", + "Ephemeral environment - SLSA Level 3" + ], + "justification": [ + "Could not find a trusted level 3 builder as a GitHub Actions workflow." + ], + "result_type": "FAILED" + } + ] + } + }, + "dependencies": { + "analyzed_deps": 0, + "unique_dep_repos": 0, + "checks_summary": [ + { + "check_id": "mcn_infer_artifact_pipeline_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_script_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_version_control_system_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_service_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_available_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_as_code_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_expectation_1", + "num_deps_pass": 0 + } + ], + "dep_status": [] + } +} diff --git a/tests/e2e/expected_results/react-pdf/react-pdf.json b/tests/e2e/expected_results/react-pdf/react-pdf.json new file mode 100644 index 000000000..85d8037f8 --- /dev/null +++ b/tests/e2e/expected_results/react-pdf/react-pdf.json @@ -0,0 +1,253 @@ +{ + "metadata": { + "timestamps": "2023-09-20 20:15:39" + }, + "target": { + "info": { + "full_name": "pkg:github.com/wojtekmaj/react-pdf@be18436b7be827eb993b2e1e4bd9230dd835a9a3", + "local_cloned_path": "git_repos/github_com/wojtekmaj/react-pdf", + "remote_path": "https://github.com/wojtekmaj/react-pdf", + "branch": "main", + "commit_hash": "be18436b7be827eb993b2e1e4bd9230dd835a9a3", + "commit_date": "2023-09-08T16:10:19+02:00" + }, + "provenances": { + "is_inferred": true, + "content": { + "github_actions": [ + { + "_type": "https://in-toto.io/Statement/v0.1", + "subject": [], + "predicateType": "https://slsa.dev/provenance/v0.2", + "predicate": { + "builder": { + "id": "https://github.com/wojtekmaj/react-pdf/blob/be18436b7be827eb993b2e1e4bd9230dd835a9a3/.github/workflows/publish.yml" + }, + "buildType": "Custom github_actions", + "invocation": { + "configSource": { + "uri": "https://github.com/wojtekmaj/react-pdf@refs/heads/main", + "digest": { + "sha1": "be18436b7be827eb993b2e1e4bd9230dd835a9a3" + }, + "entryPoint": "https://github.com/wojtekmaj/react-pdf/blob/be18436b7be827eb993b2e1e4bd9230dd835a9a3/.github/workflows/publish.yml" + }, + "parameters": {}, + "environment": {} + }, + "buildConfig": { + "jobID": "publish", + "stepID": "Publish with latest tag" + }, + "metadata": { + "buildInvocationId": "", + "buildStartedOn": "", + "buildFinishedOn": "", + "completeness": { + "parameters": "false", + "environment": "false", + "materials": "false" + }, + "reproducible": "false" + }, + "materials": [ + { + "uri": "", + "digest": {} + } + ] + } + } + ] + } + }, + "checks": { + "summary": { + "DISABLED": 0, + "FAILED": 6, + "PASSED": 4, + "SKIPPED": 0, + "UNKNOWN": 0 + }, + "results": [ + { + "check_id": "mcn_build_as_code_1", + "check_description": "The build definition and configuration executed by the build service is verifiably derived from text file definitions stored in a version control system.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + "The target repository does not use npm to deploy.", + { + "The target repository uses build tool yarn to deploy": "https://github.com/wojtekmaj/react-pdf/blob/be18436b7be827eb993b2e1e4bd9230dd835a9a3/.github/workflows/publish.yml", + "The build is triggered by": "https://github.com/wojtekmaj/react-pdf/blob/be18436b7be827eb993b2e1e4bd9230dd835a9a3/.github/workflows/publish.yml" + }, + "Deploy command: ['yarn', 'npm', 'publish', '--tag', 'latest']", + "However, could not find a passing workflow run." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_script_1", + "check_description": "Check if the target repo has a valid build script.", + "slsa_requirements": [ + "Scripted Build - SLSA Level 1" + ], + "justification": [ + "Check mcn_build_script_1 is set to PASSED because mcn_build_service_1 PASSED." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_service_1", + "check_description": "Check if the target repo has a valid build service.", + "slsa_requirements": [ + "Build service - SLSA Level 2" + ], + "justification": [ + "Check mcn_build_service_1 is set to PASSED because mcn_build_as_code_1 PASSED." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_version_control_system_1", + "check_description": "Check whether the target repo uses a version control system.", + "slsa_requirements": [ + "Version controlled - SLSA Level 2" + ], + "justification": [ + { + "This is a Git repository": "https://github.com/wojtekmaj/react-pdf" + } + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_infer_artifact_pipeline_1", + "check_description": "Detects potential pipelines from which an artifact is published.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + "Unable to find a publishing timestamp for the artifact." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_available_1", + "check_description": "Check whether the target has intoto provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Could not find any SLSA or Witness provenances." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_expectation_1", + "check_description": "Check whether the SLSA provenance for the produced artifact conforms to the expected value.", + "slsa_requirements": [ + "Provenance conforms with expectations - SLSA Level 3" + ], + "justification": [ + "Check mcn_provenance_expectation_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_level_three_1", + "check_description": "Check whether the target has SLSA provenance level 3.", + "slsa_requirements": [ + "Provenance - Non falsifiable - SLSA Level 3", + "Provenance content - Includes all build parameters - SLSA Level 3", + "Provenance content - Identifies entry point - SLSA Level 3", + "Provenance content - Identifies source code - SLSA Level 2" + ], + "justification": [ + "Check mcn_provenance_level_three_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "check_description": "Check whether the target has a level-1 witness provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Check mcn_provenance_witness_level_one_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "check_description": "Check whether the target uses a trusted SLSA level 3 builder.", + "slsa_requirements": [ + "Hermetic - SLSA Level 4", + "Isolated - SLSA Level 3", + "Parameterless - SLSA Level 4", + "Ephemeral environment - SLSA Level 3" + ], + "justification": [ + "Could not find a trusted level 3 builder as a GitHub Actions workflow." + ], + "result_type": "FAILED" + } + ] + } + }, + "dependencies": { + "analyzed_deps": 0, + "unique_dep_repos": 0, + "checks_summary": [ + { + "check_id": "mcn_infer_artifact_pipeline_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_script_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_version_control_system_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_service_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_available_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_as_code_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_expectation_1", + "num_deps_pass": 0 + } + ], + "dep_status": [] + } +} diff --git a/tests/e2e/expected_results/sget/sget.json b/tests/e2e/expected_results/sget/sget.json new file mode 100644 index 000000000..0069d6966 --- /dev/null +++ b/tests/e2e/expected_results/sget/sget.json @@ -0,0 +1,252 @@ +{ + "metadata": { + "timestamps": "2023-09-21 07:29:44" + }, + "target": { + "info": { + "full_name": "pkg:github.com/sigstore/sget@99e7b91204d391ccc76507f7079b6d2a7957489e", + "local_cloned_path": "git_repos/github_com/sigstore/sget", + "remote_path": "https://github.com/sigstore/sget", + "branch": "main", + "commit_hash": "99e7b91204d391ccc76507f7079b6d2a7957489e", + "commit_date": "2023-03-13T16:27:11+01:00" + }, + "provenances": { + "is_inferred": true, + "content": { + "github_actions": [ + { + "_type": "https://in-toto.io/Statement/v0.1", + "subject": [], + "predicateType": "https://slsa.dev/provenance/v0.2", + "predicate": { + "builder": { + "id": "https://github.com/sigstore/sget/blob/99e7b91204d391ccc76507f7079b6d2a7957489e/.github/workflows/build.yaml" + }, + "buildType": "Custom github_actions", + "invocation": { + "configSource": { + "uri": "https://github.com/sigstore/sget@refs/heads/main", + "digest": { + "sha1": "99e7b91204d391ccc76507f7079b6d2a7957489e" + }, + "entryPoint": "https://github.com/sigstore/sget/blob/99e7b91204d391ccc76507f7079b6d2a7957489e/.github/workflows/build.yaml" + }, + "parameters": {}, + "environment": {} + }, + "buildConfig": { + "jobID": "", + "stepID": "" + }, + "metadata": { + "buildInvocationId": "", + "buildStartedOn": "", + "buildFinishedOn": "", + "completeness": { + "parameters": "false", + "environment": "false", + "materials": "false" + }, + "reproducible": "false" + }, + "materials": [ + { + "uri": "", + "digest": {} + } + ] + } + } + ] + } + }, + "checks": { + "summary": { + "DISABLED": 0, + "FAILED": 7, + "PASSED": 3, + "SKIPPED": 0, + "UNKNOWN": 0 + }, + "results": [ + { + "check_id": "mcn_build_script_1", + "check_description": "Check if the target repo has a valid build script.", + "slsa_requirements": [ + "Scripted Build - SLSA Level 1" + ], + "justification": [ + "Check mcn_build_script_1 is set to PASSED because mcn_build_service_1 PASSED." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_service_1", + "check_description": "Check if the target repo has a valid build service.", + "slsa_requirements": [ + "Build service - SLSA Level 2" + ], + "justification": [ + { + "The target repository uses build tool go to deploy": "https://github.com/sigstore/sget/blob/99e7b91204d391ccc76507f7079b6d2a7957489e/.github/workflows/build.yaml", + "The build is triggered by": "https://github.com/sigstore/sget/blob/99e7b91204d391ccc76507f7079b6d2a7957489e/.github/workflows/build.yaml" + }, + "Build command: ['go', 'build', './...']", + "However, could not find a passing workflow run." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_version_control_system_1", + "check_description": "Check whether the target repo uses a version control system.", + "slsa_requirements": [ + "Version controlled - SLSA Level 2" + ], + "justification": [ + { + "This is a Git repository": "https://github.com/sigstore/sget" + } + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_as_code_1", + "check_description": "The build definition and configuration executed by the build service is verifiably derived from text file definitions stored in a version control system.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + "The target repository does not use go to deploy." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_infer_artifact_pipeline_1", + "check_description": "Detects potential pipelines from which an artifact is published.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + "Check mcn_infer_artifact_pipeline_1 is set to FAILED because mcn_build_as_code_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_available_1", + "check_description": "Check whether the target has intoto provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Could not find any SLSA or Witness provenances." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_expectation_1", + "check_description": "Check whether the SLSA provenance for the produced artifact conforms to the expected value.", + "slsa_requirements": [ + "Provenance conforms with expectations - SLSA Level 3" + ], + "justification": [ + "Check mcn_provenance_expectation_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_level_three_1", + "check_description": "Check whether the target has SLSA provenance level 3.", + "slsa_requirements": [ + "Provenance - Non falsifiable - SLSA Level 3", + "Provenance content - Includes all build parameters - SLSA Level 3", + "Provenance content - Identifies entry point - SLSA Level 3", + "Provenance content - Identifies source code - SLSA Level 2" + ], + "justification": [ + "Check mcn_provenance_level_three_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "check_description": "Check whether the target has a level-1 witness provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Check mcn_provenance_witness_level_one_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "check_description": "Check whether the target uses a trusted SLSA level 3 builder.", + "slsa_requirements": [ + "Hermetic - SLSA Level 4", + "Isolated - SLSA Level 3", + "Parameterless - SLSA Level 4", + "Ephemeral environment - SLSA Level 3" + ], + "justification": [ + "Could not find a trusted level 3 builder as a GitHub Actions workflow." + ], + "result_type": "FAILED" + } + ] + } + }, + "dependencies": { + "analyzed_deps": 0, + "unique_dep_repos": 0, + "checks_summary": [ + { + "check_id": "mcn_infer_artifact_pipeline_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_script_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_version_control_system_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_service_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_available_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_as_code_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_expectation_1", + "num_deps_pass": 0 + } + ], + "dep_status": [] + } +} diff --git a/tests/e2e/expected_results/uiv/uiv.json b/tests/e2e/expected_results/uiv/uiv.json new file mode 100644 index 000000000..92de3a6f2 --- /dev/null +++ b/tests/e2e/expected_results/uiv/uiv.json @@ -0,0 +1,253 @@ +{ + "metadata": { + "timestamps": "2023-09-21 07:27:24" + }, + "target": { + "info": { + "full_name": "pkg:github.com/uiv-lib/uiv@057b25b4db0913edab4cf728c306085e6fc20d49", + "local_cloned_path": "git_repos/github_com/uiv-lib/uiv", + "remote_path": "https://github.com/uiv-lib/uiv", + "branch": "dev", + "commit_hash": "057b25b4db0913edab4cf728c306085e6fc20d49", + "commit_date": "2023-08-27T00:14:30+00:00" + }, + "provenances": { + "is_inferred": true, + "content": { + "github_actions": [ + { + "_type": "https://in-toto.io/Statement/v0.1", + "subject": [], + "predicateType": "https://slsa.dev/provenance/v0.2", + "predicate": { + "builder": { + "id": "https://github.com/uiv-lib/uiv/blob/057b25b4db0913edab4cf728c306085e6fc20d49/.github/workflows/publish_npm.yaml" + }, + "buildType": "Custom github_actions", + "invocation": { + "configSource": { + "uri": "https://github.com/uiv-lib/uiv@refs/heads/dev", + "digest": { + "sha1": "057b25b4db0913edab4cf728c306085e6fc20d49" + }, + "entryPoint": "https://github.com/uiv-lib/uiv/blob/057b25b4db0913edab4cf728c306085e6fc20d49/.github/workflows/publish_npm.yaml" + }, + "parameters": {}, + "environment": {} + }, + "buildConfig": { + "jobID": "deploy_npm", + "stepID": "Publish NPM" + }, + "metadata": { + "buildInvocationId": "", + "buildStartedOn": "", + "buildFinishedOn": "", + "completeness": { + "parameters": "false", + "environment": "false", + "materials": "false" + }, + "reproducible": "false" + }, + "materials": [ + { + "uri": "", + "digest": {} + } + ] + } + } + ] + } + }, + "checks": { + "summary": { + "DISABLED": 0, + "FAILED": 6, + "PASSED": 4, + "SKIPPED": 0, + "UNKNOWN": 0 + }, + "results": [ + { + "check_id": "mcn_build_as_code_1", + "check_description": "The build definition and configuration executed by the build service is verifiably derived from text file definitions stored in a version control system.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + { + "The target repository uses build tool npm to deploy": "https://github.com/uiv-lib/uiv/blob/057b25b4db0913edab4cf728c306085e6fc20d49/.github/workflows/publish_npm.yaml", + "The build is triggered by": "https://github.com/uiv-lib/uiv/blob/057b25b4db0913edab4cf728c306085e6fc20d49/.github/workflows/publish_npm.yaml" + }, + "Deploy command: ['npm', 'publish']", + "However, could not find a passing workflow run.", + "The target repository does not use yarn to deploy." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_script_1", + "check_description": "Check if the target repo has a valid build script.", + "slsa_requirements": [ + "Scripted Build - SLSA Level 1" + ], + "justification": [ + "Check mcn_build_script_1 is set to PASSED because mcn_build_service_1 PASSED." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_service_1", + "check_description": "Check if the target repo has a valid build service.", + "slsa_requirements": [ + "Build service - SLSA Level 2" + ], + "justification": [ + "Check mcn_build_service_1 is set to PASSED because mcn_build_as_code_1 PASSED." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_version_control_system_1", + "check_description": "Check whether the target repo uses a version control system.", + "slsa_requirements": [ + "Version controlled - SLSA Level 2" + ], + "justification": [ + { + "This is a Git repository": "https://github.com/uiv-lib/uiv" + } + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_infer_artifact_pipeline_1", + "check_description": "Detects potential pipelines from which an artifact is published.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + "Unable to find a publishing timestamp for the artifact." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_available_1", + "check_description": "Check whether the target has intoto provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Could not find any SLSA or Witness provenances." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_expectation_1", + "check_description": "Check whether the SLSA provenance for the produced artifact conforms to the expected value.", + "slsa_requirements": [ + "Provenance conforms with expectations - SLSA Level 3" + ], + "justification": [ + "Check mcn_provenance_expectation_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_level_three_1", + "check_description": "Check whether the target has SLSA provenance level 3.", + "slsa_requirements": [ + "Provenance - Non falsifiable - SLSA Level 3", + "Provenance content - Includes all build parameters - SLSA Level 3", + "Provenance content - Identifies entry point - SLSA Level 3", + "Provenance content - Identifies source code - SLSA Level 2" + ], + "justification": [ + "Check mcn_provenance_level_three_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "check_description": "Check whether the target has a level-1 witness provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Check mcn_provenance_witness_level_one_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "check_description": "Check whether the target uses a trusted SLSA level 3 builder.", + "slsa_requirements": [ + "Hermetic - SLSA Level 4", + "Isolated - SLSA Level 3", + "Parameterless - SLSA Level 4", + "Ephemeral environment - SLSA Level 3" + ], + "justification": [ + "Could not find a trusted level 3 builder as a GitHub Actions workflow." + ], + "result_type": "FAILED" + } + ] + } + }, + "dependencies": { + "analyzed_deps": 0, + "unique_dep_repos": 0, + "checks_summary": [ + { + "check_id": "mcn_infer_artifact_pipeline_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_script_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_version_control_system_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_service_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_available_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_as_code_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_expectation_1", + "num_deps_pass": 0 + } + ], + "dep_status": [] + } +} diff --git a/tests/e2e/expected_results/urllib3/urllib3.json b/tests/e2e/expected_results/urllib3/urllib3.json index 1a24d23ef..7e37cb3b1 100644 --- a/tests/e2e/expected_results/urllib3/urllib3.json +++ b/tests/e2e/expected_results/urllib3/urllib3.json @@ -1,6 +1,6 @@ { "metadata": { - "timestamps": "2023-09-12 20:10:10" + "timestamps": "2023-09-22 14:22:34" }, "target": { "info": { @@ -20,51 +20,51 @@ "predicateType": "https://slsa.dev/provenance/v0.2", "subject": [ { - "name": "urllib3-2.0.4-py3-none-any.whl", + "name": "urllib3-2.0.5-py3-none-any.whl", "digest": { - "sha256": "de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4" + "sha256": "ef16afa8ba34a1f989db38e1dbbe0c302e4289a47856990d0682e374563ce35e" } }, { - "name": "urllib3-2.0.4.tar.gz", + "name": "urllib3-2.0.5.tar.gz", "digest": { - "sha256": "8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11" + "sha256": "13abf37382ea2ce6fb744d4dad67838eec857c9f4f57009891805e0b5e123594" } } ], "predicate": { "builder": { - "id": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.7.0" + "id": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v1.9.0" }, "buildType": "https://github.com/slsa-framework/slsa-github-generator/generic@v1", "invocation": { "configSource": { - "uri": "git+https://github.com/urllib3/urllib3@refs/tags/2.0.4", + "uri": "git+https://github.com/urllib3/urllib3@refs/tags/v2.0.5", "digest": { - "sha1": "c9fa144545eedb5dc4a2cc3f255e95602a1d7db0" + "sha1": "d9f85a749488188c286cd50606d159874db94d5f" }, "entryPoint": ".github/workflows/publish.yml" }, "parameters": {}, "environment": { - "github_actor": "illia-v", - "github_actor_id": "17710133", + "github_actor": "pquentin", + "github_actor_id": "42327", "github_base_ref": "", "github_event_name": "push", "github_event_payload": { - "after": "d267c99f7e890ff22e136c34d29be802d9c2e773", + "after": "d4e424a471c79f245740a3734567e7402c036620", "base_ref": null, "before": "0000000000000000000000000000000000000000", "commits": [], - "compare": "https://github.com/urllib3/urllib3/compare/2.0.4", + "compare": "https://github.com/urllib3/urllib3/compare/v2.0.5", "created": true, "deleted": false, "forced": false, "head_commit": { "author": { - "email": "64815328+Eutropios@users.noreply.github.com", - "name": "Noah Jenner", - "username": "Eutropios" + "email": "quentin.pradet@gmail.com", + "name": "Quentin Pradet", + "username": "pquentin" }, "committer": { "email": "noreply@github.com", @@ -72,11 +72,11 @@ "username": "web-flow" }, "distinct": true, - "id": "c9fa144545eedb5dc4a2cc3f255e95602a1d7db0", - "message": "Release version 2.0.4 (#3084)\n\nCo-authored-by: Illia Volochii ", - "timestamp": "2023-07-19T17:46:02+03:00", - "tree_id": "e61f50347e7bb803a0c8942ba63fe917c8424f77", - "url": "https://github.com/urllib3/urllib3/commit/c9fa144545eedb5dc4a2cc3f255e95602a1d7db0" + "id": "d9f85a749488188c286cd50606d159874db94d5f", + "message": "Release 2.0.5", + "timestamp": "2023-09-20T08:59:31+02:00", + "tree_id": "842632ede50bc641555c90779642ab521e0c1401", + "url": "https://github.com/urllib3/urllib3/commit/d9f85a749488188c286cd50606d159874db94d5f" }, "organization": { "avatar_url": "https://avatars.githubusercontent.com/u/26825299?v=4", @@ -93,10 +93,10 @@ "url": "https://api.github.com/orgs/urllib3" }, "pusher": { - "email": "illia.volochii@gmail.com", - "name": "illia-v" + "email": "quentin.pradet@gmail.com", + "name": "pquentin" }, - "ref": "refs/tags/2.0.4", + "ref": "refs/tags/v2.0.5", "repository": { "allow_forking": true, "archive_url": "https://api.github.com/repos/urllib3/urllib3/{archive_format}{/ref}", @@ -119,8 +119,8 @@ "downloads_url": "https://api.github.com/repos/urllib3/urllib3/downloads", "events_url": "https://api.github.com/repos/urllib3/urllib3/events", "fork": false, - "forks": 1078, - "forks_count": 1078, + "forks": 1092, + "forks_count": 1092, "forks_url": "https://api.github.com/repos/urllib3/urllib3/forks", "full_name": "urllib3/urllib3", "git_commits_url": "https://api.github.com/repos/urllib3/urllib3/git/commits{/sha}", @@ -159,8 +159,8 @@ "name": "urllib3", "node_id": "MDEwOlJlcG9zaXRvcnkyNDEwNjc2", "notifications_url": "https://api.github.com/repos/urllib3/urllib3/notifications{?since,all,participating}", - "open_issues": 125, - "open_issues_count": 125, + "open_issues": 130, + "open_issues_count": 130, "organization": "urllib3", "owner": { "avatar_url": "https://avatars.githubusercontent.com/u/26825299?v=4", @@ -186,12 +186,12 @@ }, "private": false, "pulls_url": "https://api.github.com/repos/urllib3/urllib3/pulls{/number}", - "pushed_at": 1689779927, + "pushed_at": 1695193235, "releases_url": "https://api.github.com/repos/urllib3/urllib3/releases{/id}", - "size": 7242, + "size": 6839, "ssh_url": "git@github.com:urllib3/urllib3.git", - "stargazers": 3452, - "stargazers_count": 3452, + "stargazers": 3485, + "stargazers_count": 3485, "stargazers_url": "https://api.github.com/repos/urllib3/urllib3/stargazers", "statuses_url": "https://api.github.com/repos/urllib3/urllib3/statuses/{sha}", "subscribers_url": "https://api.github.com/repos/urllib3/urllib3/subscribers", @@ -206,48 +206,48 @@ "urllib3" ], "trees_url": "https://api.github.com/repos/urllib3/urllib3/git/trees{/sha}", - "updated_at": "2023-07-19T02:19:14Z", + "updated_at": "2023-09-19T20:11:25Z", "url": "https://github.com/urllib3/urllib3", "visibility": "public", - "watchers": 3452, - "watchers_count": 3452, + "watchers": 3485, + "watchers_count": 3485, "web_commit_signoff_required": false }, "sender": { - "avatar_url": "https://avatars.githubusercontent.com/u/17710133?v=4", - "events_url": "https://api.github.com/users/illia-v/events{/privacy}", - "followers_url": "https://api.github.com/users/illia-v/followers", - "following_url": "https://api.github.com/users/illia-v/following{/other_user}", - "gists_url": "https://api.github.com/users/illia-v/gists{/gist_id}", + "avatar_url": "https://avatars.githubusercontent.com/u/42327?v=4", + "events_url": "https://api.github.com/users/pquentin/events{/privacy}", + "followers_url": "https://api.github.com/users/pquentin/followers", + "following_url": "https://api.github.com/users/pquentin/following{/other_user}", + "gists_url": "https://api.github.com/users/pquentin/gists{/gist_id}", "gravatar_id": "", - "html_url": "https://github.com/illia-v", - "id": 17710133, - "login": "illia-v", - "node_id": "MDQ6VXNlcjE3NzEwMTMz", - "organizations_url": "https://api.github.com/users/illia-v/orgs", - "received_events_url": "https://api.github.com/users/illia-v/received_events", - "repos_url": "https://api.github.com/users/illia-v/repos", + "html_url": "https://github.com/pquentin", + "id": 42327, + "login": "pquentin", + "node_id": "MDQ6VXNlcjQyMzI3", + "organizations_url": "https://api.github.com/users/pquentin/orgs", + "received_events_url": "https://api.github.com/users/pquentin/received_events", + "repos_url": "https://api.github.com/users/pquentin/repos", "site_admin": false, - "starred_url": "https://api.github.com/users/illia-v/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/illia-v/subscriptions", + "starred_url": "https://api.github.com/users/pquentin/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/pquentin/subscriptions", "type": "User", - "url": "https://api.github.com/users/illia-v" + "url": "https://api.github.com/users/pquentin" } }, "github_head_ref": "", - "github_ref": "refs/tags/2.0.4", + "github_ref": "refs/tags/v2.0.5", "github_ref_type": "tag", "github_repository_id": "2410676", "github_repository_owner": "urllib3", "github_repository_owner_id": "26825299", "github_run_attempt": "1", - "github_run_id": "5600993171", - "github_run_number": "21", - "github_sha1": "c9fa144545eedb5dc4a2cc3f255e95602a1d7db0" + "github_run_id": "6245105149", + "github_run_number": "22", + "github_sha1": "d9f85a749488188c286cd50606d159874db94d5f" } }, "metadata": { - "buildInvocationID": "5600993171-1", + "buildInvocationID": "6245105149-1", "completeness": { "parameters": true, "environment": false, @@ -257,9 +257,9 @@ }, "materials": [ { - "uri": "git+https://github.com/urllib3/urllib3@refs/tags/2.0.4", + "uri": "git+https://github.com/urllib3/urllib3@refs/tags/v2.0.5", "digest": { - "sha1": "c9fa144545eedb5dc4a2cc3f255e95602a1d7db0" + "sha1": "d9f85a749488188c286cd50606d159874db94d5f" } } ] @@ -352,7 +352,7 @@ ], "justification": [ "Successfully verified level 3: ", - "verify passed : urllib3-2.0.4-py3-none-any.whl,verify passed : urllib3-2.0.4.tar.gz" + "verify passed : urllib3-2.0.5-py3-none-any.whl,verify passed : urllib3-2.0.5.tar.gz" ], "result_type": "PASSED" }, @@ -416,35 +416,35 @@ "unique_dep_repos": 0, "checks_summary": [ { - "check_id": "mcn_provenance_expectation_1", + "check_id": "mcn_infer_artifact_pipeline_1", "num_deps_pass": 0 }, { - "check_id": "mcn_provenance_witness_level_one_1", + "check_id": "mcn_build_script_1", "num_deps_pass": 0 }, { - "check_id": "mcn_provenance_available_1", + "check_id": "mcn_version_control_system_1", "num_deps_pass": 0 }, { - "check_id": "mcn_infer_artifact_pipeline_1", + "check_id": "mcn_build_service_1", "num_deps_pass": 0 }, { - "check_id": "mcn_build_as_code_1", + "check_id": "mcn_trusted_builder_level_three_1", "num_deps_pass": 0 }, { - "check_id": "mcn_version_control_system_1", + "check_id": "mcn_provenance_witness_level_one_1", "num_deps_pass": 0 }, { - "check_id": "mcn_trusted_builder_level_three_1", + "check_id": "mcn_provenance_available_1", "num_deps_pass": 0 }, { - "check_id": "mcn_build_script_1", + "check_id": "mcn_build_as_code_1", "num_deps_pass": 0 }, { @@ -452,7 +452,7 @@ "num_deps_pass": 0 }, { - "check_id": "mcn_build_service_1", + "check_id": "mcn_provenance_expectation_1", "num_deps_pass": 0 } ], diff --git a/tests/e2e/expected_results/yoga/yoga.json b/tests/e2e/expected_results/yoga/yoga.json new file mode 100644 index 000000000..82bc387f3 --- /dev/null +++ b/tests/e2e/expected_results/yoga/yoga.json @@ -0,0 +1,260 @@ +{ + "metadata": { + "timestamps": "2023-09-21 07:28:37" + }, + "target": { + "info": { + "full_name": "pkg:github.com/facebook/yoga@f8e2bc0875c145c429d0e865c9b83a40f65b3070", + "local_cloned_path": "git_repos/github_com/facebook/yoga", + "remote_path": "https://github.com/facebook/yoga", + "branch": "main", + "commit_hash": "f8e2bc0875c145c429d0e865c9b83a40f65b3070", + "commit_date": "2023-09-06T09:50:43-07:00" + }, + "provenances": { + "is_inferred": true, + "content": { + "github_actions": [ + { + "_type": "https://in-toto.io/Statement/v0.1", + "subject": [], + "predicateType": "https://slsa.dev/provenance/v0.2", + "predicate": { + "builder": { + "id": "https://github.com/facebook/yoga/blob/f8e2bc0875c145c429d0e865c9b83a40f65b3070/.github/workflows/publish-npm-release.yml" + }, + "buildType": "Custom github_actions", + "invocation": { + "configSource": { + "uri": "https://github.com/facebook/yoga@refs/heads/main", + "digest": { + "sha1": "f8e2bc0875c145c429d0e865c9b83a40f65b3070" + }, + "entryPoint": "https://github.com/facebook/yoga/blob/f8e2bc0875c145c429d0e865c9b83a40f65b3070/.github/workflows/publish-npm-release.yml" + }, + "parameters": {}, + "environment": {} + }, + "buildConfig": { + "jobID": "publish", + "stepID": "yarn publish" + }, + "metadata": { + "buildInvocationId": "", + "buildStartedOn": "", + "buildFinishedOn": "", + "completeness": { + "parameters": "false", + "environment": "false", + "materials": "false" + }, + "reproducible": "false" + }, + "materials": [ + { + "uri": "", + "digest": {} + } + ] + } + } + ], + "Maven Central Registry": [] + } + }, + "checks": { + "summary": { + "DISABLED": 0, + "FAILED": 6, + "PASSED": 4, + "SKIPPED": 0, + "UNKNOWN": 0 + }, + "results": [ + { + "check_id": "mcn_build_as_code_1", + "check_description": "The build definition and configuration executed by the build service is verifiably derived from text file definitions stored in a version control system.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + { + "The target repository uses build tool gradle to deploy": "https://github.com/facebook/yoga/blob/f8e2bc0875c145c429d0e865c9b83a40f65b3070/.github/workflows/publish-android-snashot.yml", + "The build is triggered by": "https://github.com/facebook/yoga/blob/f8e2bc0875c145c429d0e865c9b83a40f65b3070/.github/workflows/publish-android-snashot.yml" + }, + "Deploy command: ['./gradlew', 'publishToSonatype']", + "However, could not find a passing workflow run.", + "The target repository does not use npm to deploy.", + { + "The target repository uses build tool yarn to deploy": "https://github.com/facebook/yoga/blob/f8e2bc0875c145c429d0e865c9b83a40f65b3070/.github/workflows/publish-npm-release.yml", + "The build is triggered by": "https://github.com/facebook/yoga/blob/f8e2bc0875c145c429d0e865c9b83a40f65b3070/.github/workflows/publish-npm-release.yml" + }, + "Deploy command: ['yarn', 'publish']", + "However, could not find a passing workflow run." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_script_1", + "check_description": "Check if the target repo has a valid build script.", + "slsa_requirements": [ + "Scripted Build - SLSA Level 1" + ], + "justification": [ + "Check mcn_build_script_1 is set to PASSED because mcn_build_service_1 PASSED." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_build_service_1", + "check_description": "Check if the target repo has a valid build service.", + "slsa_requirements": [ + "Build service - SLSA Level 2" + ], + "justification": [ + "Check mcn_build_service_1 is set to PASSED because mcn_build_as_code_1 PASSED." + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_version_control_system_1", + "check_description": "Check whether the target repo uses a version control system.", + "slsa_requirements": [ + "Version controlled - SLSA Level 2" + ], + "justification": [ + { + "This is a Git repository": "https://github.com/facebook/yoga" + } + ], + "result_type": "PASSED" + }, + { + "check_id": "mcn_infer_artifact_pipeline_1", + "check_description": "Detects potential pipelines from which an artifact is published.", + "slsa_requirements": [ + "Build as code - SLSA Level 3" + ], + "justification": [ + "Unable to find a publishing timestamp for the artifact." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_available_1", + "check_description": "Check whether the target has intoto provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Could not find any SLSA or Witness provenances." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_expectation_1", + "check_description": "Check whether the SLSA provenance for the produced artifact conforms to the expected value.", + "slsa_requirements": [ + "Provenance conforms with expectations - SLSA Level 3" + ], + "justification": [ + "Check mcn_provenance_expectation_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_level_three_1", + "check_description": "Check whether the target has SLSA provenance level 3.", + "slsa_requirements": [ + "Provenance - Non falsifiable - SLSA Level 3", + "Provenance content - Includes all build parameters - SLSA Level 3", + "Provenance content - Identifies entry point - SLSA Level 3", + "Provenance content - Identifies source code - SLSA Level 2" + ], + "justification": [ + "Check mcn_provenance_level_three_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "check_description": "Check whether the target has a level-1 witness provenance.", + "slsa_requirements": [ + "Provenance - Available - SLSA Level 1", + "Provenance content - Identifies build instructions - SLSA Level 1", + "Provenance content - Identifies artifacts - SLSA Level 1", + "Provenance content - Identifies builder - SLSA Level 1" + ], + "justification": [ + "Check mcn_provenance_witness_level_one_1 is set to FAILED because mcn_provenance_available_1 FAILED." + ], + "result_type": "FAILED" + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "check_description": "Check whether the target uses a trusted SLSA level 3 builder.", + "slsa_requirements": [ + "Hermetic - SLSA Level 4", + "Isolated - SLSA Level 3", + "Parameterless - SLSA Level 4", + "Ephemeral environment - SLSA Level 3" + ], + "justification": [ + "Could not find a trusted level 3 builder as a GitHub Actions workflow." + ], + "result_type": "FAILED" + } + ] + } + }, + "dependencies": { + "analyzed_deps": 0, + "unique_dep_repos": 0, + "checks_summary": [ + { + "check_id": "mcn_infer_artifact_pipeline_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_script_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_version_control_system_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_service_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_trusted_builder_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_witness_level_one_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_available_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_build_as_code_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_level_three_1", + "num_deps_pass": 0 + }, + { + "check_id": "mcn_provenance_expectation_1", + "num_deps_pass": 0 + } + ], + "dep_status": [] + } +} diff --git a/tests/slsa_analyzer/build_tool/__snapshots__/test_go.ambr b/tests/slsa_analyzer/build_tool/__snapshots__/test_go.ambr new file mode 100644 index 000000000..b2f5db1c6 --- /dev/null +++ b/tests/slsa_analyzer/build_tool/__snapshots__/test_go.ambr @@ -0,0 +1,10 @@ +# serializer version: 1 +# name: test_get_build_dirs[root_go_mod-go.mod] + list([ + PosixPath('.'), + ]) +# --- +# name: test_get_build_dirs[no_go_mod-dummyfile.txt] + list([ + ]) +# --- diff --git a/tests/slsa_analyzer/build_tool/__snapshots__/test_npm.ambr b/tests/slsa_analyzer/build_tool/__snapshots__/test_npm.ambr new file mode 100644 index 000000000..83dd8ecaf --- /dev/null +++ b/tests/slsa_analyzer/build_tool/__snapshots__/test_npm.ambr @@ -0,0 +1,20 @@ +# serializer version: 1 +# name: test_get_build_dirs[mock_repo0] + list([ + PosixPath('.'), + ]) +# --- +# name: test_get_build_dirs[mock_repo1] + list([ + PosixPath('.'), + ]) +# --- +# name: test_get_build_dirs[mock_repo2] + list([ + PosixPath('project'), + ]) +# --- +# name: test_get_build_dirs[mock_repo3] + list([ + ]) +# --- diff --git a/tests/slsa_analyzer/build_tool/__snapshots__/test_yarn.ambr b/tests/slsa_analyzer/build_tool/__snapshots__/test_yarn.ambr new file mode 100644 index 000000000..83dd8ecaf --- /dev/null +++ b/tests/slsa_analyzer/build_tool/__snapshots__/test_yarn.ambr @@ -0,0 +1,20 @@ +# serializer version: 1 +# name: test_get_build_dirs[mock_repo0] + list([ + PosixPath('.'), + ]) +# --- +# name: test_get_build_dirs[mock_repo1] + list([ + PosixPath('.'), + ]) +# --- +# name: test_get_build_dirs[mock_repo2] + list([ + PosixPath('project'), + ]) +# --- +# name: test_get_build_dirs[mock_repo3] + list([ + ]) +# --- diff --git a/tests/slsa_analyzer/build_tool/mock_repos/go_repos/no_go_mod/dummy_file.txt b/tests/slsa_analyzer/build_tool/mock_repos/go_repos/no_go_mod/dummy_file.txt new file mode 100644 index 000000000..e965047ad --- /dev/null +++ b/tests/slsa_analyzer/build_tool/mock_repos/go_repos/no_go_mod/dummy_file.txt @@ -0,0 +1 @@ +Hello diff --git a/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/nested_package/project/package.json b/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/nested_package/project/package.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/no_package/dummyfile.txt b/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/no_package/dummyfile.txt new file mode 100644 index 000000000..e965047ad --- /dev/null +++ b/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/no_package/dummyfile.txt @@ -0,0 +1 @@ +Hello diff --git a/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/root_package/package.json b/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/root_package/package.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/root_package_packagelock/package-lock.json b/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/root_package_packagelock/package-lock.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/root_package_packagelock/package.json b/tests/slsa_analyzer/build_tool/mock_repos/npm_repos/root_package_packagelock/package.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/nested_package/project/package.json b/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/nested_package/project/package.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/no_package/dummyfile.txt b/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/no_package/dummyfile.txt new file mode 100644 index 000000000..e965047ad --- /dev/null +++ b/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/no_package/dummyfile.txt @@ -0,0 +1 @@ +Hello diff --git a/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/root_package/package.json b/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/root_package/package.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/root_package_packagelock/package-lock.json b/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/root_package_packagelock/package-lock.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/root_package_packagelock/package.json b/tests/slsa_analyzer/build_tool/mock_repos/yarn_repos/root_package_packagelock/package.json new file mode 100644 index 000000000..e69de29bb diff --git a/tests/slsa_analyzer/build_tool/test_go.py b/tests/slsa_analyzer/build_tool/test_go.py new file mode 100644 index 000000000..4aa32cd30 --- /dev/null +++ b/tests/slsa_analyzer/build_tool/test_go.py @@ -0,0 +1,54 @@ +# Copyright (c) 2023 - 2023, 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 module tests the Go build functions.""" + +from pathlib import Path + +import pytest + +from macaron.slsa_analyzer.build_tool.go import Go +from tests.slsa_analyzer.mock_git_utils import prepare_repo_for_testing + + +@pytest.mark.parametrize( + ("folder", "file"), + [ + ("root_go_mod", "go.mod"), + ("no_go_mod", "dummyfile.txt"), + ], +) +def test_get_build_dirs(snapshot: list, tmp_path: Path, go_tool: Go, folder: str, file: str) -> None: + """Test discovering build directories.""" + # Since there's issues having 2 go.mod files in the same project, we make + # it on the fly for this test + proj_dir = tmp_path.joinpath(folder) + proj_dir.mkdir(parents=True) + + with open(proj_dir.joinpath(file), "w", encoding="utf-8"): + assert list(go_tool.get_build_dirs(str(proj_dir))) == snapshot + + +@pytest.mark.parametrize( + ("folder", "file", "expected_value"), + [ + ("root_go_mod", "go.mod", True), + ("no_go_mod", "dummyfile.txt", False), + ], +) +def test_go_build_tool( + go_tool: Go, macaron_path: str, tmp_path: Path, folder: str, file: str, expected_value: bool +) -> None: + """Test the Go build tool.""" + base_dir = Path(__file__).parent + + # Making directories with a go.mod but no actual Go project seems to cause issues + # for the pre-commit hooks (errors like go: warning: "./..." matched no packages); + # as such it is easiest for this test to just create/delete the go.mod files + # macaron looks for on the fly instead of managing a proper project within the mock repos. + proj_dir = tmp_path.joinpath(folder) + proj_dir.mkdir(parents=True) + + with open(proj_dir.joinpath(file), "w", encoding="utf-8"): + ctx = prepare_repo_for_testing(proj_dir, macaron_path, base_dir) + assert go_tool.is_detected(ctx.component.repository.fs_path) == expected_value diff --git a/tests/slsa_analyzer/build_tool/test_npm.py b/tests/slsa_analyzer/build_tool/test_npm.py new file mode 100644 index 000000000..184fe5027 --- /dev/null +++ b/tests/slsa_analyzer/build_tool/test_npm.py @@ -0,0 +1,41 @@ +# Copyright (c) 2023 - 2023, 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 module tests the NPM build functions.""" + +from pathlib import Path + +import pytest + +from macaron.slsa_analyzer.build_tool.npm import NPM +from tests.slsa_analyzer.mock_git_utils import prepare_repo_for_testing + + +@pytest.mark.parametrize( + "mock_repo", + [ + Path(__file__).parent.joinpath("mock_repos", "npm_repos", "root_package"), + Path(__file__).parent.joinpath("mock_repos", "npm_repos", "root_package_packagelock"), + Path(__file__).parent.joinpath("mock_repos", "npm_repos", "nested_package"), + Path(__file__).parent.joinpath("mock_repos", "npm_repos", "no_package"), + ], +) +def test_get_build_dirs(snapshot: list, npm_tool: NPM, mock_repo: Path) -> None: + """Test discovering build directories.""" + assert list(npm_tool.get_build_dirs(str(mock_repo))) == snapshot + + +@pytest.mark.parametrize( + ("mock_repo", "expected_value"), + [ + (Path(__file__).parent.joinpath("mock_repos", "npm_repos", "root_package"), True), + (Path(__file__).parent.joinpath("mock_repos", "npm_repos", "root_package_packagelock"), True), + (Path(__file__).parent.joinpath("mock_repos", "npm_repos", "nested_package"), True), + (Path(__file__).parent.joinpath("mock_repos", "npm_repos", "no_package"), False), + ], +) +def test_npm_build_tool(npm_tool: NPM, macaron_path: str, mock_repo: str, expected_value: bool) -> None: + """Test the NPM build tool.""" + base_dir = Path(__file__).parent + ctx = prepare_repo_for_testing(mock_repo, macaron_path, base_dir) + assert npm_tool.is_detected(ctx.component.repository.fs_path) == expected_value diff --git a/tests/slsa_analyzer/build_tool/test_yarn.py b/tests/slsa_analyzer/build_tool/test_yarn.py new file mode 100644 index 000000000..a0498850e --- /dev/null +++ b/tests/slsa_analyzer/build_tool/test_yarn.py @@ -0,0 +1,41 @@ +# Copyright (c) 2023 - 2023, 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 module tests the Yarn build functions.""" + +from pathlib import Path + +import pytest + +from macaron.slsa_analyzer.build_tool.yarn import Yarn +from tests.slsa_analyzer.mock_git_utils import prepare_repo_for_testing + + +@pytest.mark.parametrize( + "mock_repo", + [ + Path(__file__).parent.joinpath("mock_repos", "yarn_repos", "root_package"), + Path(__file__).parent.joinpath("mock_repos", "yarn_repos", "root_package_packagelock"), + Path(__file__).parent.joinpath("mock_repos", "yarn_repos", "nested_package"), + Path(__file__).parent.joinpath("mock_repos", "yarn_repos", "no_package"), + ], +) +def test_get_build_dirs(snapshot: list, yarn_tool: Yarn, mock_repo: Path) -> None: + """Test discovering build directories.""" + assert list(yarn_tool.get_build_dirs(str(mock_repo))) == snapshot + + +@pytest.mark.parametrize( + ("mock_repo", "expected_value"), + [ + (Path(__file__).parent.joinpath("mock_repos", "yarn_repos", "root_package"), True), + (Path(__file__).parent.joinpath("mock_repos", "yarn_repos", "root_package_packagelock"), True), + (Path(__file__).parent.joinpath("mock_repos", "yarn_repos", "nested_package"), True), + (Path(__file__).parent.joinpath("mock_repos", "yarn_repos", "no_package"), False), + ], +) +def test_yarn_build_tool(yarn_tool: Yarn, macaron_path: str, mock_repo: str, expected_value: bool) -> None: + """Test the yarn build tool.""" + base_dir = Path(__file__).parent + ctx = prepare_repo_for_testing(mock_repo, macaron_path, base_dir) + assert yarn_tool.is_detected(ctx.component.repository.fs_path) == expected_value