aboutsummaryrefslogtreecommitdiff
path: root/infra/ci
diff options
context:
space:
mode:
authorAbhishek Arya <inferno@chromium.org>2020-06-12 14:39:16 -0700
committerGitHub <noreply@github.com>2020-06-12 14:39:16 -0700
commit7101ec4d4bac7f4e97e6b0e12d077a00b7e105b2 (patch)
treede19698c32e43accd80f3ee372d98861cf86ba96 /infra/ci
parentad4557e4ad194d91cd2e9a4815aacbcd1cc1fbf6 (diff)
downloadoss-fuzz-7101ec4d4bac7f4e97e6b0e12d077a00b7e105b2.tar.gz
Add Github Actions CI. (#3971)
Diffstat (limited to 'infra/ci')
-rwxr-xr-xinfra/ci/build.py148
-rw-r--r--infra/ci/requirements.txt6
2 files changed, 154 insertions, 0 deletions
diff --git a/infra/ci/build.py b/infra/ci/build.py
new file mode 100755
index 000000000..f93c18a09
--- /dev/null
+++ b/infra/ci/build.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+# Copyright 2019 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+################################################################################
+"""Build modified projects."""
+
+from __future__ import print_function
+
+import os
+import re
+import sys
+import subprocess
+import yaml
+
+DEFAULT_ARCHITECTURES = ['x86_64']
+DEFAULT_ENGINES = ['afl', 'honggfuzz', 'libfuzzer']
+DEFAULT_SANITIZERS = ['address', 'undefined']
+
+
+def get_modified_buildable_projects():
+ """Returns a list of all the projects modified in this commit that have a
+ build.sh file."""
+ output = subprocess.check_output(['git', 'diff', '--name-only',
+ 'FETCH_HEAD']).decode()
+ projects_regex = '.*projects/(?P<name>.*)/.*\n'
+ modified_projects = set(re.findall(projects_regex, output))
+ projects_dir = os.path.join(get_oss_fuzz_root(), 'projects')
+ # Filter out projects without Dockerfile files since new projects and reverted
+ # projects frequently don't have them. In these cases we don't want Travis's
+ # builds to fail.
+ modified_buildable_projects = []
+ for project in modified_projects:
+ if not os.path.exists(os.path.join(projects_dir, project, 'Dockerfile')):
+ print('Project {0} does not have Dockerfile. skipping build.'.format(
+ project))
+ continue
+ modified_buildable_projects.append(project)
+ return modified_buildable_projects
+
+
+def get_oss_fuzz_root():
+ """Get the absolute path of the root of the oss-fuzz checkout."""
+ script_path = os.path.realpath(__file__)
+ return os.path.abspath(
+ os.path.dirname(os.path.dirname(os.path.dirname(script_path))))
+
+
+def execute_helper_command(helper_command):
+ """Execute |helper_command| using helper.py."""
+ root = get_oss_fuzz_root()
+ script_path = os.path.join(root, 'infra', 'helper.py')
+ command = ['python', script_path] + helper_command
+ print('Running command: %s' % ' '.join(command))
+ subprocess.check_call(command)
+
+
+def build_fuzzers(project, engine, sanitizer, architecture):
+ """Execute helper.py's build_fuzzers command on |project|. Build the fuzzers
+ with |engine| and |sanitizer| for |architecture|."""
+ execute_helper_command([
+ 'build_fuzzers', project, '--engine', engine, '--sanitizer', sanitizer,
+ '--architecture', architecture
+ ])
+
+
+def check_build(project, engine, sanitizer, architecture):
+ """Execute helper.py's check_build command on |project|, assuming it was most
+ recently built with |engine| and |sanitizer| for |architecture|."""
+ execute_helper_command([
+ 'check_build', project, '--engine', engine, '--sanitizer', sanitizer,
+ '--architecture', architecture
+ ])
+
+
+def should_build(project_yaml):
+ """Is the build specified by travis enabled in the |project_yaml|?"""
+
+ def is_enabled(env_var, yaml_name, defaults):
+ """Is the value of |env_var| enabled in |project_yaml| (in the |yaml_name|
+ section)? Uses |defaults| if |yaml_name| section is unspecified."""
+ return os.getenv(env_var) in project_yaml.get(yaml_name, defaults)
+
+ return (is_enabled('ENGINE', 'fuzzing_engines', DEFAULT_ENGINES) and
+ is_enabled('SANITIZER', 'sanitizers', DEFAULT_SANITIZERS) and
+ is_enabled('ARCHITECTURE', 'architectures', DEFAULT_ARCHITECTURES))
+
+
+def build_project(project):
+ """Do the build of |project| that is specified by the environment variables -
+ SANITIZER, ENGINE, and ARCHITECTURE."""
+ root = get_oss_fuzz_root()
+ project_yaml_path = os.path.join(root, 'projects', project, 'project.yaml')
+ with open(project_yaml_path) as file_handle:
+ project_yaml = yaml.safe_load(file_handle)
+
+ if project_yaml.get('disabled', False):
+ print('Project {0} is disabled, skipping build.'.format(project))
+ return
+
+ engine = os.getenv('ENGINE')
+ sanitizer = os.getenv('SANITIZER')
+ architecture = os.getenv('ARCHITECTURE')
+
+ if not should_build(project_yaml):
+ print(('Specified build: engine: {0}, sanitizer: {1}, architecture: {2} '
+ 'not enabled for this project: {3}. skipping build.').format(
+ engine, sanitizer, architecture, project))
+
+ return
+
+ print('Building project', project)
+ build_fuzzers(project, engine, sanitizer, architecture)
+
+ if engine != 'none':
+ check_build(project, engine, sanitizer, architecture)
+
+
+def main():
+ """Build modified projects on travis."""
+ projects = get_modified_buildable_projects()
+ failed_projects = []
+ for project in projects:
+ try:
+ build_project(project)
+ except subprocess.CalledProcessError:
+ failed_projects.append(project)
+
+ if failed_projects:
+ print('Failed projects:', ' '.join(failed_projects))
+ return 1
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/infra/ci/requirements.txt b/infra/ci/requirements.txt
new file mode 100644
index 000000000..2ddcb47d4
--- /dev/null
+++ b/infra/ci/requirements.txt
@@ -0,0 +1,6 @@
+# Requirements for submitting code changes to infra/ (needed by presubmit.py).
+pylint==2.4.4
+yapf==0.28.0
+PyYAML==5.1
+pyfakefs==3.7.1
+parameterized==0.7.4