diff --git a/.dockerignore b/.dockerignore index 1e2f1e16..39b31bd2 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1 @@ -hack/libgit2/ +build/libgit2/ diff --git a/.github/workflows/cifuzz.yaml b/.github/workflows/cifuzz.yaml new file mode 100644 index 00000000..91fd397b --- /dev/null +++ b/.github/workflows/cifuzz.yaml @@ -0,0 +1,24 @@ +name: CIFuzz +on: + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + Fuzzing: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Restore Go cache + uses: actions/cache@v1 + with: + path: /home/runner/work/_temp/_github_home/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: Smoke test Fuzzers + run: make fuzz-smoketest diff --git a/Dockerfile b/Dockerfile index 02d61a4f..18d9b6d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG GO_VERSION=1.17 ARG XX_VERSION=1.1.0 ARG LIBGIT2_IMG=ghcr.io/fluxcd/golang-with-libgit2 -ARG LIBGIT2_TAG=libgit2-1.1.1-6 +ARG LIBGIT2_TAG=libgit2-1.1.1-7 FROM ${LIBGIT2_IMG}:${LIBGIT2_TAG} AS libgit2-libs diff --git a/Makefile b/Makefile index 4d50d240..ccfa5bf7 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CRD_OPTIONS ?= crd:crdVersions=v1 # Base image used to build the Go binary LIBGIT2_IMG ?= ghcr.io/fluxcd/golang-with-libgit2 -LIBGIT2_TAG ?= libgit2-1.1.1-6 +LIBGIT2_TAG ?= libgit2-1.1.1-7 # Allows for defining additional Docker buildx arguments, # e.g. '--push'. @@ -236,6 +236,25 @@ ENVTEST = $(GOBIN)/setup-envtest setup-envtest: ## Download envtest-setup locally if necessary. $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest) +# Build fuzzers +fuzz-build: $(LIBGIT2) + rm -rf $(shell pwd)/build/fuzz/ + mkdir -p $(shell pwd)/build/fuzz/out/ + + docker build . --tag local-fuzzing:latest -f tests/fuzz/Dockerfile.builder + docker run --rm \ + -e FUZZING_LANGUAGE=go -e SANITIZER=address \ + -e CIFUZZ_DEBUG='True' -e OSS_FUZZ_PROJECT_NAME=fluxcd \ + -v "$(shell pwd)/build/fuzz/out":/out \ + local-fuzzing:latest + +fuzz-smoketest: fuzz-build + docker run --rm \ + -v "$(shell pwd)/build/fuzz/out":/out \ + -v "$(shell pwd)/tests/fuzz/oss_fuzz_run.sh":/runner.sh \ + local-fuzzing:latest \ + bash -c "/runner.sh" + # go-install-tool will 'go install' any package $2 and install it to $1. define go-install-tool @[ -f $(1) ] || { \ diff --git a/tests/fuzz/Dockerfile.builder b/tests/fuzz/Dockerfile.builder new file mode 100644 index 00000000..33356dec --- /dev/null +++ b/tests/fuzz/Dockerfile.builder @@ -0,0 +1,8 @@ +FROM gcr.io/oss-fuzz-base/base-builder-go + +RUN apt-get update && apt-get install -y cmake pkg-config + +COPY ./ $GOPATH/src/github.com/fluxcd/image-automation-controller/ +COPY ./tests/fuzz/oss_fuzz_build.sh $SRC/build.sh + +WORKDIR $SRC diff --git a/tests/fuzz/go.mod b/tests/fuzz/go.mod new file mode 100644 index 00000000..78d80e99 --- /dev/null +++ b/tests/fuzz/go.mod @@ -0,0 +1,3 @@ +module github.com/fluxcd/image-automation-controller/tests/fuzz + +go 1.17 diff --git a/tests/fuzz/image_update_fuzzer.go b/tests/fuzz/image_update_fuzzer.go new file mode 100644 index 00000000..3640bf64 --- /dev/null +++ b/tests/fuzz/image_update_fuzzer.go @@ -0,0 +1,520 @@ +//go:build gofuzz +// +build gofuzz + +/* +Copyright 2021 The Flux authors + +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. +*/ + +package controllers + +import ( + "context" + "embed" + "fmt" + "io/fs" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "sync" + "time" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + "github.com/fluxcd/image-automation-controller/controllers" + "github.com/fluxcd/image-automation-controller/pkg/update" + "github.com/fluxcd/pkg/gittestserver" + "github.com/fluxcd/pkg/runtime/testenv" + "github.com/go-git/go-billy/v5/memfs" + "github.com/go-git/go-git/v5" + gogit "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/storage/memory" + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/types" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/kubernetes/scheme" + + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/manager" + + image_automationv1 "github.com/fluxcd/image-automation-controller/api/v1beta1" + image_reflectv1 "github.com/fluxcd/image-reflector-controller/api/v1beta1" + sourcev1 "github.com/fluxcd/source-controller/api/v1beta1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var ( + cfgFuzz *rest.Config + k8sClient client.Client + imageAutoReconcilerFuzz *controllers.ImageUpdateAutomationReconciler + testEnvFuzz *testenv.Environment + initter sync.Once +) + +const defaultBinVersion = "1.23" + +//go:embed testdata/crds +var testFiles embed.FS + +func envtestBinVersion() string { + if binVersion := os.Getenv("ENVTEST_BIN_VERSION"); binVersion != "" { + return binVersion + } + return defaultBinVersion +} + +func ensureDependencies(setupReconcilers func(manager.Manager)) error { + if _, err := os.Stat("/.dockerenv"); os.IsNotExist(err) { + return nil + } + + if os.Getenv("KUBEBUILDER_ASSETS") == "" { + binVersion := envtestBinVersion() + cmd := exec.Command("/usr/bin/bash", "-c", fmt.Sprintf(`go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest && \ + /root/go/bin/setup-envtest use -p path %s`, binVersion)) + + cmd.Env = append(os.Environ(), "GOPATH=/root/go") + assetsPath, err := cmd.Output() + if err != nil { + return err + } + os.Setenv("KUBEBUILDER_ASSETS", string(assetsPath)) + } + + // Output all embedded testdata files + embedDirs := []string{"testdata/crds"} + for _, dir := range embedDirs { + err := os.MkdirAll(dir, 0o755) + if err != nil { + return fmt.Errorf("mkdir %s: %v", dir, err) + } + + templates, err := fs.ReadDir(testFiles, dir) + if err != nil { + return fmt.Errorf("reading embedded dir: %v", err) + } + + for _, template := range templates { + fileName := fmt.Sprintf("%s/%s", dir, template.Name()) + fmt.Println(fileName) + + data, err := testFiles.ReadFile(fileName) + if err != nil { + return fmt.Errorf("reading embedded file %s: %v", fileName, err) + } + + os.WriteFile(fileName, data, 0o644) + if err != nil { + return fmt.Errorf("writing %s: %v", fileName, err) + } + } + } + + testEnv := &envtest.Environment{ + CRDDirectoryPaths: []string{ + filepath.Join("testdata", "crds"), + }, + } + fmt.Println("Starting the test environment") + cfg, err := testEnv.Start() + if err != nil { + panic(fmt.Sprintf("Failed to start the test environment manager: %v", err)) + } + + utilruntime.Must(sourcev1.AddToScheme(scheme.Scheme)) + utilruntime.Must(image_reflectv1.AddToScheme(scheme.Scheme)) + utilruntime.Must(image_automationv1.AddToScheme(scheme.Scheme)) + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + if err != nil { + panic(err) + } + if k8sClient == nil { + panic("cfg is nil but should not be") + } + + k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: scheme.Scheme, + }) + if err != nil { + panic(err) + } + + setupReconcilers(k8sManager) + + time.Sleep(2 * time.Second) + go func() { + fmt.Println("Starting k8sManager...") + utilruntime.Must(k8sManager.Start(context.TODO())) + }() + + return nil +} + +// This fuzzer randomized 2 things: +// 1: The files in the git repository +// 2: The values of ImageUpdateAutomationSpec +// and ImagePolicy resources +func FuzzImageUpdateReconciler(data []byte) int { + initter.Do(func() { + utilruntime.Must(ensureDependencies(func(m manager.Manager) { + utilruntime.Must((&controllers.ImageUpdateAutomationReconciler{ + Client: m.GetClient(), + Scheme: scheme.Scheme, + }).SetupWithManager(m, controllers.ImageUpdateAutomationReconcilerOptions{MaxConcurrentReconciles: 4})) + })) + }) + + f := fuzz.NewConsumer(data) + + // We start by creating a lot of the values that + // need for the various resources later on + runes := "abcdefghijklmnopqrstuvwxyz1234567890" + branch, err := f.GetStringFrom(runes, 80) + if err != nil { + return 0 + } + repPath, err := f.GetStringFrom(runes, 80) + if err != nil { + return 0 + } + repositoryPath := "/config-" + repPath + ".git" + + namespaceName, err := f.GetStringFrom(runes, 59) + if err != nil { + return 0 + } + + gitRepoKeyName, err := f.GetStringFrom(runes, 80) + if err != nil { + return 0 + } + + username, err := f.GetStringFrom(runes, 80) + if err != nil { + return 0 + } + password, err := f.GetStringFrom(runes, 80) + if err != nil { + return 0 + } + + ipSpec := image_reflectv1.ImagePolicySpec{} + err = f.GenerateStruct(&ipSpec) + if err != nil { + return 0 + } + + ipStatus := image_reflectv1.ImagePolicyStatus{} + err = f.GenerateStruct(&ipStatus) + if err != nil { + return 0 + } + + iuaSpec := image_automationv1.ImageUpdateAutomationSpec{} + err = f.GenerateStruct(&iuaSpec) + if err != nil { + return 0 + } + gitSpec := &image_automationv1.GitSpec{} + err = f.GenerateStruct(&gitSpec) + if err != nil { + return 0 + } + + policyKeyName, err := f.GetStringFrom(runes, 80) + if err != nil { + return 0 + } + + updateKeyName, err := f.GetStringFrom("abcdefghijklmnopqrstuvwxy.-", 120) + if err != nil { + return 0 + } + + // Create random git files + gitPath, err := os.MkdirTemp("", "git-dir-") + if err != nil { + return 0 + } + defer os.RemoveAll(gitPath) + err = f.CreateFiles(gitPath) + if err != nil { + return 0 + } + + // Done with creating the random values + + // Create a namespace + namespace := &corev1.Namespace{} + namespace.Name = namespaceName + err = k8sClient.Create(context.Background(), namespace) + if err != nil { + return 0 + } + defer func() { + err = k8sClient.Delete(context.Background(), namespace) + if err != nil { + panic(err) + } + time.Sleep(80 * time.Millisecond) + }() + + // Set up git-related stuff + gitServer, err := gittestserver.NewTempGitServer() + if err != nil { + return 0 + } + gitServer.Auth(username, password) + gitServer.AutoCreate() + err = gitServer.StartHTTP() + if err != nil { + return 0 + } + defer func() { + gitServer.StopHTTP() + os.RemoveAll(gitServer.Root()) + }() + gitServer.KeyDir(filepath.Join(gitServer.Root(), "keys")) + err = gitServer.ListenSSH() + if err != nil { + return 0 + } + err = initGitRepo(gitServer, gitPath, branch, repositoryPath) + if err != nil { + return 0 + } + repoURL := gitServer.HTTPAddressWithCredentials() + repositoryPath + // Done with setting up git related stuff + + // Create git repository object + gitRepoKey := types.NamespacedName{ + Name: "image-auto-" + gitRepoKeyName, + Namespace: namespace.Name, + } + + gitRepo := &sourcev1.GitRepository{ + ObjectMeta: metav1.ObjectMeta{ + Name: gitRepoKey.Name, + Namespace: namespace.Name, + }, + Spec: sourcev1.GitRepositorySpec{ + URL: repoURL, + Interval: metav1.Duration{Duration: time.Minute}, + }, + } + err = k8sClient.Create(context.Background(), gitRepo) + if err != nil { + return 0 + } + defer k8sClient.Delete(context.Background(), gitRepo) + + // Create image policy object + policyKey := types.NamespacedName{ + Name: "policy-" + policyKeyName, + Namespace: namespace.Name, + } + policy := &image_reflectv1.ImagePolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: policyKey.Name, + Namespace: policyKey.Namespace, + }, + Spec: ipSpec, + Status: ipStatus, + } + err = k8sClient.Create(context.Background(), policy) + if err != nil { + return 0 + } + err = k8sClient.Status().Update(context.Background(), policy) + if err != nil { + return 0 + } + + // Create ImageUpdateAutomation object + updateKey := types.NamespacedName{ + Namespace: namespace.Name, + Name: updateKeyName, + } + + // Setting these fields manually to help the fuzzer + gitSpec.Checkout.Reference.Branch = branch + iuaSpec.GitSpec = gitSpec + iuaSpec.SourceRef.Kind = "GitRepository" + iuaSpec.SourceRef.Name = gitRepoKey.Name + iuaSpec.Update.Strategy = image_automationv1.UpdateStrategySetters + + iua := &image_automationv1.ImageUpdateAutomation{ + ObjectMeta: metav1.ObjectMeta{ + Name: updateKey.Name, + Namespace: updateKey.Namespace, + }, + Spec: iuaSpec, + } + err = k8sClient.Create(context.Background(), iua) + if err != nil { + return 0 + } + defer k8sClient.Delete(context.Background(), iua) + time.Sleep(time.Millisecond * 70) + return 1 +} + +// A fuzzer that is more focused on UpdateWithSetters +// that the reconciler fuzzer is +func FuzzUpdateWithSetters(data []byte) int { + f := fuzz.NewConsumer(data) + + // Create dir1 + tmp1, err := ioutil.TempDir("", "fuzztest1") + if err != nil { + return 0 + } + defer os.RemoveAll(tmp1) + // Add files to dir1 + err = f.CreateFiles(tmp1) + if err != nil { + return 0 + } + + // Create dir2 + tmp2, err := ioutil.TempDir("", "fuzztest2") + if err != nil { + return 0 + } + defer os.RemoveAll(tmp2) + + // Create policies + policies := make([]image_reflectv1.ImagePolicy, 0) + noOfPolicies, err := f.GetInt() + if err != nil { + return 0 + } + for i := 0; i < noOfPolicies%10; i++ { + policy := image_reflectv1.ImagePolicy{} + err = f.GenerateStruct(&policy) + if err != nil { + return 0 + } + policies = append(policies, policy) + } + + // Call the target + _, _ = update.UpdateWithSetters(logr.Discard(), tmp1, tmp2, policies) + return 1 +} + +// Initialise a git server with a repo including the files in dir. +func initGitRepo(gitServer *gittestserver.GitServer, fixture, branch, repositoryPath string) error { + fs := memfs.New() + repo, err := git.Init(memory.NewStorage(), fs) + if err != nil { + return err + } + + err = populateRepoFromFixture(repo, fixture) + if err != nil { + return err + } + + working, err := repo.Worktree() + if err != nil { + return err + } + if err = working.Checkout(&git.CheckoutOptions{ + Branch: plumbing.NewBranchReferenceName(branch), + Create: true, + }); err != nil { + return err + } + + remote, err := repo.CreateRemote(&config.RemoteConfig{ + Name: "origin", + URLs: []string{gitServer.HTTPAddressWithCredentials() + repositoryPath}, + }) + if err != nil { + return err + } + + return remote.Push(&git.PushOptions{ + RefSpecs: []config.RefSpec{ + config.RefSpec(fmt.Sprintf("refs/heads/%s:refs/heads/%s", branch, branch)), + }, + }) +} + +func populateRepoFromFixture(repo *gogit.Repository, fixture string) error { + working, err := repo.Worktree() + if err != nil { + return err + } + fs := working.Filesystem + + if err = filepath.Walk(fixture, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return fs.MkdirAll(fs.Join(path[len(fixture):]), info.Mode()) + } + // copy symlinks as-is, so I can test what happens with broken symlinks + if info.Mode()&os.ModeSymlink > 0 { + target, err := os.Readlink(path) + if err != nil { + return err + } + return fs.Symlink(target, path[len(fixture):]) + } + + fileBytes, err := os.ReadFile(path) + if err != nil { + return err + } + + ff, err := fs.Create(path[len(fixture):]) + if err != nil { + return err + } + defer ff.Close() + + _, err = ff.Write(fileBytes) + return err + }); err != nil { + return err + } + + _, err = working.Add(".") + if err != nil { + return err + } + + if _, err = working.Commit("Initial revision from "+fixture, &gogit.CommitOptions{ + Author: &object.Signature{ + Name: "Testbot", + Email: "test@example.com", + When: time.Now(), + }, + }); err != nil { + return err + } + + return nil +} diff --git a/tests/fuzz/oss_fuzz_build.sh b/tests/fuzz/oss_fuzz_build.sh new file mode 100755 index 00000000..93c1eda7 --- /dev/null +++ b/tests/fuzz/oss_fuzz_build.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash + +# Copyright 2022 The Flux authors +# +# 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. + +set -euxo pipefail + +LIBGIT2_TAG="${LIBGIT2_TAG:-libgit2-1.1.1-7}" +GOPATH="${GOPATH:-/root/go}" +GO_SRC="${GOPATH}/src" +PROJECT_PATH="github.com/fluxcd/image-automation-controller" + +cd "${GO_SRC}" + +pushd "${PROJECT_PATH}" + +export TARGET_DIR="$(/bin/pwd)/build/libgit2/${LIBGIT2_TAG}" + +# For most cases, libgit2 will already be present. +# The exception being at the oss-fuzz integration. +if [ ! -d "${TARGET_DIR}" ]; then + curl -o output.tar.gz -LO "https://github.com/fluxcd/golang-with-libgit2/releases/download/${LIBGIT2_TAG}/linux-$(uname -m)-libs.tar.gz" + + DIR=libgit2-linux + NEW_DIR="$(/bin/pwd)/build/libgit2/${LIBGIT2_TAG}" + INSTALLED_DIR="/home/runner/work/golang-with-libgit2/golang-with-libgit2/build/${DIR}" + + mkdir -p ./build/libgit2 + + tar -xf output.tar.gz + rm output.tar.gz + mv "${DIR}" "${LIBGIT2_TAG}" + mv "${LIBGIT2_TAG}/" "./build/libgit2" + + # Update the prefix paths included in the .pc files. + # This will make it easier to update to the location in which they will be used. + find "${NEW_DIR}" -type f -name "*.pc" | xargs -I {} sed -i "s;${INSTALLED_DIR};${NEW_DIR};g" {} +fi + +apt-get update && apt-get install -y pkg-config + +export TARGET_DIR="$(/bin/pwd)/build/libgit2/${LIBGIT2_TAG}" +export CGO_ENABLED=1 +export LIBRARY_PATH="${TARGET_DIR}/lib:${TARGET_DIR}/lib64" +export PKG_CONFIG_PATH="${TARGET_DIR}/lib/pkgconfig:${TARGET_DIR}/lib64/pkgconfig" +export CGO_CFLAGS="-I${TARGET_DIR}/include -I${TARGET_DIR}/include/openssl" +export CGO_LDFLAGS="$(pkg-config --libs --static --cflags libssh2 openssl libgit2)" + +go mod tidy -compat=1.17 + +popd + +pushd "${PROJECT_PATH}/tests/fuzz" + +# Version of the source-controller from which to get the GitRepository CRD. +# Change this if you bump the source-controller/api version in go.mod. +SOURCE_VER=v0.21.1 + +# Version of the image-reflector-controller from which to get the ImagePolicy CRD. +# Change this if you bump the image-reflector-controller/api version in go.mod. +REFLECTOR_VER=v0.16.0 + +# Setup files to be embedded into controllers_fuzzer.go's testFiles variable. +mkdir -p testdata/crds +cp ../../config/crd/bases/*.yaml testdata/crds/ + +if [ -d "../../controllers/testdata/crds" ]; then + cp ../../controllers/testdata/crds/*.yaml testdata/crds +# Fetch the CRDs if not present since we need them when running fuzz tests on CI. +else + curl -s --fail https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml -o testdata/crds/gitrepositories.yaml + + curl -s --fail https://raw.githubusercontent.com/fluxcd/image-reflector-controller/${REFLECTOR_VER}/config/crd/bases/image.toolkit.fluxcd.io_imagepolicies.yaml -o testdata/crds/imagepolicies.yaml +fi + +go mod tidy -compat=1.17 + +# ref: https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/compile_go_fuzzer +go-fuzz -tags gofuzz -func=FuzzImageUpdateReconciler -o fuzz_image_update_reconciler.a . +clang -o /out/fuzz_image_update_reconciler \ + fuzz_image_update_reconciler.a \ + "${TARGET_DIR}/lib/libgit2.a" \ + "${TARGET_DIR}/lib/libssh2.a" \ + "${TARGET_DIR}/lib/libz.a" \ + "${TARGET_DIR}/lib64/libssl.a" \ + "${TARGET_DIR}/lib64/libcrypto.a" \ + -fsanitize=fuzzer + +go-fuzz -tags gofuzz -func=FuzzUpdateWithSetters -o fuzz_update_with_setters.a . +clang -o /out/fuzz_update_with_setters \ + fuzz_update_with_setters.a \ + "${TARGET_DIR}/lib/libgit2.a" \ + "${TARGET_DIR}/lib/libssh2.a" \ + "${TARGET_DIR}/lib/libz.a" \ + "${TARGET_DIR}/lib64/libssl.a" \ + "${TARGET_DIR}/lib64/libcrypto.a" \ + -fsanitize=fuzzer + +popd diff --git a/tests/fuzz/oss_fuzz_run.sh b/tests/fuzz/oss_fuzz_run.sh new file mode 100755 index 00000000..4c87f489 --- /dev/null +++ b/tests/fuzz/oss_fuzz_run.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Copyright 2022 The Flux authors +# +# 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. + +set -euxo pipefail + +# run each fuzzer once to ensure they are working properly +find /out -type f -name "fuzz*" -exec echo {} -runs=1 \; | bash -e