aboutsummaryrefslogtreecommitdiffhomepage
path: root/infra/cifuzz/affected_fuzz_targets.py
diff options
context:
space:
mode:
authorGravatar Jonathan Metzman <metzman@chromium.org>2021-01-20 07:25:08 -0800
committerGravatar Jonathan Metzman <metzman@chromium.org>2021-01-20 07:25:08 -0800
commitddb0add036e34a85d6ab4a711d7c29d7fe15ac19 (patch)
treef8445c6a2875b8cf5e08891cef507a80b6492bf4 /infra/cifuzz/affected_fuzz_targets.py
parent0be9a235b81a82c2bafd84a645ada249b6f8aefb (diff)
fuzzers->fuzz targets and finish affected_fuzz_targets module
Diffstat (limited to 'infra/cifuzz/affected_fuzz_targets.py')
-rw-r--r--infra/cifuzz/affected_fuzz_targets.py100
1 files changed, 91 insertions, 9 deletions
diff --git a/infra/cifuzz/affected_fuzz_targets.py b/infra/cifuzz/affected_fuzz_targets.py
index ca81752b..b5f51ad6 100644
--- a/infra/cifuzz/affected_fuzz_targets.py
+++ b/infra/cifuzz/affected_fuzz_targets.py
@@ -11,7 +11,9 @@
# 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.
-"""Module for dealing with fuzzers affected by the change-under-test (CUT)."""
+"""Module for dealing with fuzz targets affected by the change-under-test
+(CUT)."""
+import logging
import os
import sys
@@ -21,11 +23,91 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import utils
-def fix_git_repo_for_diff(repo_dir):
- """Fixes git repos cloned by the "checkout" action so that diffing works on
- them."""
- command = [
- 'git', 'symbolic-ref', 'refs/remotes/origin/HEAD',
- 'refs/remotes/origin/master'
- ]
- return utils.execute(command, location=repo_dir)
+def remove_unaffected_fuzz_targets(project_name, out_dir, files_changed,
+ repo_path):
+ """Removes all non affected fuzz targets in the out directory.
+
+ Args:
+ project_name: The name of the relevant OSS-Fuzz project.
+ out_dir: The location of the fuzz target binaries.
+ files_changed: A list of files changed compared to HEAD.
+ repo_path: The location of the OSS-Fuzz repo in the docker image.
+
+ This function will not delete fuzz targets unless it knows that the fuzz
+ targets are unaffected. For example, this means that fuzz targets which don't
+ have coverage data on will not be deleted.
+ """
+ if not files_changed:
+ # Don't remove any fuzz targets if there is no difference from HEAD.
+ logging.info('No files changed.')
+ return
+
+ logging.info('Files changed in PR: %s', files_changed)
+
+ fuzz_target_paths = utils.get_fuzz_targets(out_dir)
+ if not fuzz_target_paths:
+ # Nothing to remove.
+ logging.error('No fuzz targets found in out dir.')
+ return
+
+ coverage_getter = coverage.OSSFuzzCoveragGetter(project_name,
+ repo_path)
+ if coverage_getter.fuzzer_stats_url:
+ # Don't remove any fuzz targets unless we have data.
+ logging.error('Could not download latest coverage report.')
+ return
+
+ affected_fuzz_targets = get_affected_fuzz_targets(
+ coverage_getter, fuzz_target_paths, files_changed)
+
+ if not affected_fuzz_targets:
+ logging.info('No affected fuzz targets detected, keeping all as fallback.')
+ return
+
+ logging.info('Using affected fuzz targets: %s.', affected_fuzz_targets)
+ unaffected_fuzz_targets = set(fuzz_target_paths) - affected_fuzz_targets
+ logging.info('Removing unaffected fuzz targets: %s.', unaffected_fuzz_targets)
+
+ # Remove all the targets that are not affected.
+ for fuzz_target_path in unaffected_fuzz_targets:
+ try:
+ os.remove(fuzz_target_path)
+ except OSError as error:
+ logging.error('%s occurred while removing file %s',
+ error, fuzz_target_path)
+
+
+def is_fuzz_target_affected(coverage_getter, fuzz_target_path, files_changed):
+ """Returns True if a fuzz target (|fuzz_target_path| is affected by
+ |files_changed|."""
+ fuzz_target = os.path.basename(fuzz_target_path)
+ covered_files = coverage_getter.get_files_covered_by_target(fuzz_target)
+ if not covered_files:
+ # Assume a fuzz target is affected if we can't get its coverage from
+ # OSS-Fuzz.
+ logging.info('Could not get coverage for %s. Treating as affected.',
+ fuzz_target)
+ return True
+
+ logging.info('Fuzz target %s is affected by: %s',
+ fuzz_target, covered_files)
+ for filename in files_changed:
+ if filename in covered_files:
+ logging.info('Fuzz target %s is affected by changed file: %s',
+ fuzz_target, filename)
+ return True
+
+ logging.info('Fuzz target %s is not affected.', fuzz_target)
+ return False
+
+
+def get_affected_fuzz_targets(
+ coverage_getter, fuzz_target_paths, files_changed):
+ """Returns a list of paths of affected targets."""
+ affected_fuzz_targets = set()
+ for fuzz_target_path in fuzz_target_paths:
+ if is_fuzz_target_affected(
+ coverage_getter, fuzz_target_path, files_changed):
+ affected_fuzz_targets.add(fuzz_target_path)
+
+ return affected_fuzz_targets