aboutsummaryrefslogtreecommitdiff
path: root/infra
diff options
context:
space:
mode:
authorjonathanmetzman <31354670+jonathanmetzman@users.noreply.github.com>2021-02-19 11:54:15 -0800
committerGitHub <noreply@github.com>2021-02-19 11:54:15 -0800
commit28b35e36fea5284c45f56d92e06153cc5b502945 (patch)
tree5c591387c20e1ea129a74fd8070ef4b9711f1e65 /infra
parentbf0720d322057c505eb462bab697d874e27e5e98 (diff)
downloadoss-fuzz-28b35e36fea5284c45f56d92e06153cc5b502945.tar.gz
[CIFuzz] Support languages non-C++ projects (e.g. Python projects) (#5222)
Allow use of non-C++ projects by specifying the language in the workflow file. Fixes #5195
Diffstat (limited to 'infra')
-rw-r--r--infra/cifuzz/actions/build_fuzzers/action.yml5
-rw-r--r--infra/cifuzz/actions/run_fuzzers/action.yml5
-rw-r--r--infra/cifuzz/build_fuzzers.py12
-rw-r--r--infra/cifuzz/build_fuzzers_entrypoint.py3
-rw-r--r--infra/cifuzz/build_fuzzers_test.py17
-rw-r--r--infra/cifuzz/config_utils.py21
-rw-r--r--infra/cifuzz/config_utils_test.py29
7 files changed, 77 insertions, 15 deletions
diff --git a/infra/cifuzz/actions/build_fuzzers/action.yml b/infra/cifuzz/actions/build_fuzzers/action.yml
index 2919db40e..35ff010b3 100644
--- a/infra/cifuzz/actions/build_fuzzers/action.yml
+++ b/infra/cifuzz/actions/build_fuzzers/action.yml
@@ -5,6 +5,10 @@ inputs:
oss-fuzz-project-name:
description: 'Name of the corresponding OSS-Fuzz project.'
required: true
+ language:
+ description: 'Programming language project is written in.'
+ required: false
+ default: 'c++'
dry-run:
description: 'If set, run the action without actually reporting a failure.'
default: false
@@ -25,6 +29,7 @@ runs:
image: '../../../build_fuzzers.Dockerfile'
env:
OSS_FUZZ_PROJECT_NAME: ${{ inputs.oss-fuzz-project-name }}
+ LANGUAGE: ${{ inputs.language }}
DRY_RUN: ${{ inputs.dry-run}}
ALLOWED_BROKEN_TARGETS_PERCENTAGE: ${{ inputs.allowed-broken-targets-percentage}}
SANITIZER: ${{ inputs.sanitizer }}
diff --git a/infra/cifuzz/actions/run_fuzzers/action.yml b/infra/cifuzz/actions/run_fuzzers/action.yml
index 582133c74..aec899608 100644
--- a/infra/cifuzz/actions/run_fuzzers/action.yml
+++ b/infra/cifuzz/actions/run_fuzzers/action.yml
@@ -5,6 +5,10 @@ inputs:
oss-fuzz-project-name:
description: 'The OSS-Fuzz project name.'
required: true
+ language:
+ description: 'Programming language project is written in.'
+ required: false
+ default: 'c++'
fuzz-seconds:
description: 'The total time allotted for fuzzing in seconds.'
required: true
@@ -31,6 +35,7 @@ runs:
image: '../../../run_fuzzers.Dockerfile'
env:
OSS_FUZZ_PROJECT_NAME: ${{ inputs.oss-fuzz-project-name }}
+ LANGUAGE: ${{ inputs.language }}
FUZZ_SECONDS: ${{ inputs.fuzz-seconds }}
DRY_RUN: ${{ inputs.dry-run}}
SANITIZER: ${{ inputs.sanitizer }}
diff --git a/infra/cifuzz/build_fuzzers.py b/infra/cifuzz/build_fuzzers.py
index a4342a413..2dae6c986 100644
--- a/infra/cifuzz/build_fuzzers.py
+++ b/infra/cifuzz/build_fuzzers.py
@@ -77,7 +77,8 @@ class Builder: # pylint: disable=too-many-instance-attributes
def build_fuzzers(self):
"""Moves the source code we want to fuzz into the project builder and builds
the fuzzers from that source code. Returns True on success."""
- docker_args = get_common_docker_args(self.config.sanitizer)
+ docker_args = get_common_docker_args(self.config.sanitizer,
+ self.config.language)
container = utils.get_container_name()
if container:
@@ -185,7 +186,7 @@ def build_fuzzers(config):
return builder.build()
-def get_common_docker_args(sanitizer):
+def get_common_docker_args(sanitizer, language):
"""Returns a list of common docker arguments."""
return [
'--cap-add',
@@ -199,12 +200,13 @@ def get_common_docker_args(sanitizer):
'-e',
'CIFUZZ=True',
'-e',
- 'FUZZING_LANGUAGE=c++', # FIXME: Add proper support.
+ 'FUZZING_LANGUAGE=' + language,
]
def check_fuzzer_build(out_dir,
- sanitizer='address',
+ sanitizer,
+ language,
allowed_broken_targets_percentage=None):
"""Checks the integrity of the built fuzzers.
@@ -222,7 +224,7 @@ def check_fuzzer_build(out_dir,
logging.error('No fuzzers found in out directory: %s.', out_dir)
return False
- command = get_common_docker_args(sanitizer)
+ command = get_common_docker_args(sanitizer, language)
if allowed_broken_targets_percentage is not None:
command += [
diff --git a/infra/cifuzz/build_fuzzers_entrypoint.py b/infra/cifuzz/build_fuzzers_entrypoint.py
index 9c4b98215..ddae68197 100644
--- a/infra/cifuzz/build_fuzzers_entrypoint.py
+++ b/infra/cifuzz/build_fuzzers_entrypoint.py
@@ -75,7 +75,8 @@ def main():
# yapf: disable
if build_fuzzers.check_fuzzer_build(
out_dir,
- sanitizer=config.sanitizer,
+ config.sanitizer,
+ config.language,
allowed_broken_targets_percentage=config.allowed_broken_targets_percentage
):
# yapf: enable
diff --git a/infra/cifuzz/build_fuzzers_test.py b/infra/cifuzz/build_fuzzers_test.py
index 2d27356d2..2329894b9 100644
--- a/infra/cifuzz/build_fuzzers_test.py
+++ b/infra/cifuzz/build_fuzzers_test.py
@@ -251,6 +251,9 @@ class BuildFuzzersIntegrationTest(unittest.TestCase):
class CheckFuzzerBuildTest(unittest.TestCase):
"""Tests the check_fuzzer_build function in the cifuzz module."""
+ SANITIZER = 'address'
+ LANGUAGE = 'c++'
+
def setUp(self):
self.tmp_dir_obj = tempfile.TemporaryDirectory()
self.test_files_path = os.path.join(self.tmp_dir_obj.name, 'test_files')
@@ -262,15 +265,21 @@ class CheckFuzzerBuildTest(unittest.TestCase):
def test_correct_fuzzer_build(self):
"""Checks check_fuzzer_build function returns True for valid fuzzers."""
test_fuzzer_dir = os.path.join(self.test_files_path, 'out')
- self.assertTrue(build_fuzzers.check_fuzzer_build(test_fuzzer_dir))
+ self.assertTrue(
+ build_fuzzers.check_fuzzer_build(test_fuzzer_dir, self.SANITIZER,
+ self.LANGUAGE))
def test_not_a_valid_fuzz_path(self):
"""Tests that False is returned when a bad path is given."""
- self.assertFalse(build_fuzzers.check_fuzzer_build('not/a/valid/path'))
+ self.assertFalse(
+ build_fuzzers.check_fuzzer_build('not/a/valid/path', self.SANITIZER,
+ self.LANGUAGE))
def test_not_a_valid_fuzzer(self):
"""Checks a directory that exists but does not have fuzzers is False."""
- self.assertFalse(build_fuzzers.check_fuzzer_build(self.test_files_path))
+ self.assertFalse(
+ build_fuzzers.check_fuzzer_build(self.test_files_path, self.SANITIZER,
+ self.LANGUAGE))
@mock.patch('helper.docker_run')
def test_allow_broken_fuzz_targets_percentage(self, mocked_docker_run):
@@ -279,6 +288,8 @@ class CheckFuzzerBuildTest(unittest.TestCase):
mocked_docker_run.return_value = 0
test_fuzzer_dir = os.path.join(TEST_FILES_PATH, 'out')
build_fuzzers.check_fuzzer_build(test_fuzzer_dir,
+ self.SANITIZER,
+ self.LANGUAGE,
allowed_broken_targets_percentage='0')
self.assertIn('-e ALLOWED_BROKEN_TARGETS_PERCENTAGE=0',
' '.join(mocked_docker_run.call_args[0][0]))
diff --git a/infra/cifuzz/config_utils.py b/infra/cifuzz/config_utils.py
index fd1871497..7ee3444b3 100644
--- a/infra/cifuzz/config_utils.py
+++ b/infra/cifuzz/config_utils.py
@@ -62,6 +62,19 @@ def get_project_src_path(workspace):
return os.path.join(workspace, path)
+DEFAULT_LANGUAGE = 'c++'
+
+
+def _get_language():
+ """Returns the project language."""
+ # Get language from environment. We took this approach because the convenience
+ # given to OSS-Fuzz users by not making them specify the language again (and
+ # getting it from the project.yaml) is outweighed by the complexity in
+ # implementing this. A lot of the complexity comes from our unittests not
+ # setting a proper projet at this point.
+ return os.getenv('LANGUAGE', DEFAULT_LANGUAGE)
+
+
# pylint: disable=too-few-public-methods,too-many-instance-attributes
@@ -81,14 +94,20 @@ class BaseConfig:
self.dry_run = _is_dry_run()
self.sanitizer = _get_sanitizer()
self.build_integration_path = os.getenv('BUILD_INTEGRATION_PATH')
+ self.language = _get_language()
event_path = os.getenv('GITHUB_EVENT_PATH')
self.is_github = bool(event_path)
logging.debug('Is github: %s.', self.is_github)
@property
+ def is_internal(self):
+ """Returns True if this is an OSS-Fuzz project."""
+ return not self.build_integration_path
+
+ @property
def platform(self):
"""Returns the platform CIFuzz is runnning on."""
- if self.build_integration_path:
+ if not self.is_internal:
return self.Platform.EXTERNAL_GITHUB
if self.is_github:
return self.Platform.INTERNAL_GITHUB
diff --git a/infra/cifuzz/config_utils_test.py b/infra/cifuzz/config_utils_test.py
index 71e7450fa..6f87bd4c5 100644
--- a/infra/cifuzz/config_utils_test.py
+++ b/infra/cifuzz/config_utils_test.py
@@ -13,19 +13,38 @@
# limitations under the License.
"""Module for getting the configuration CIFuzz needs to run."""
import os
-import sys
import unittest
import config_utils
-
-# pylint: disable=wrong-import-position,import-error
-sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
import test_helpers
# pylint: disable=no-self-use
+class BaseConfigTest(unittest.TestCase):
+ """Tests for BaseConfig."""
+
+ def setUp(self):
+ test_helpers.patch_environ(self)
+
+ def _create_config(self):
+ return config_utils.BuildFuzzersConfig()
+
+ def test_language_default(self):
+ """Tests that the correct default language is set."""
+ os.environ['BUILD_INTEGRATION_PATH'] = '/path'
+ config = self._create_config()
+ self.assertEqual(config.language, 'c++')
+
+ def test_language(self):
+ """Tests that the correct language is set."""
+ os.environ['BUILD_INTEGRATION_PATH'] = '/path'
+ language = 'python'
+ os.environ['LANGUAGE'] = language
+ config = self._create_config()
+ self.assertEqual(config.language, language)
+
+
class BuildFuzzersConfigTest(unittest.TestCase):
"""Tests for BuildFuzzersConfig."""