diff --git a/projects/argo/Dockerfile b/projects/argo/Dockerfile new file mode 100644 index 000000000..b1e144581 --- /dev/null +++ b/projects/argo/Dockerfile @@ -0,0 +1,21 @@ +# Copyright 2021 Google LLC +# +# 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. +# +################################################################################ + +FROM gcr.io/oss-fuzz-base/base-builder-go +RUN git clone --depth 1 https://github.com/argoproj/argo-cd +RUN git clone --depth 1 https://github.com/argoproj/argo-workflows +COPY build.sh normalizer_fuzzer.go workflow_validation_fuzzer.go $SRC/ +WORKDIR $SRC/argo-cd diff --git a/projects/argo/build.sh b/projects/argo/build.sh new file mode 100644 index 000000000..b32f79fdc --- /dev/null +++ b/projects/argo/build.sh @@ -0,0 +1,23 @@ +#!/bin/bash -eu +# Copyright 2021 Google LLC +# +# 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. +# +################################################################################ + +mv $SRC/normalizer_fuzzer.go $SRC/argo-cd/util/argo/normalizers/ +compile_go_fuzzer github.com/argoproj/argo-cd/v2/util/argo/normalizers FuzzNormalize fuzz_normalize + +mv $SRC/workflow_validation_fuzzer.go $SRC/argo-workflows/workflow/validate/ +cd $SRC/argo-workflows +compile_go_fuzzer github.com/argoproj/argo-workflows/v3/workflow/validate FuzzValidateWorkflow fuzz_validate_workflow diff --git a/projects/argo/normalizer_fuzzer.go b/projects/argo/normalizer_fuzzer.go new file mode 100644 index 000000000..087664808 --- /dev/null +++ b/projects/argo/normalizer_fuzzer.go @@ -0,0 +1,78 @@ +// Copyright 2021 Google LLC +// +// 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 normalizers + +import ( + "encoding/json" + "strings" + + fuzz "github.com/AdaLogics/go-fuzz-headers" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/yaml" +) + +func UnstructuredForFuzzing(text string) (*unstructured.Unstructured, error) { + un := &unstructured.Unstructured{} + var err error + if strings.HasPrefix(text, "{") { + err = json.Unmarshal([]byte(text), &un) + } else { + err = yaml.Unmarshal([]byte(text), &un) + } + if err != nil { + return nil, err + } + return un, nil +} + +func FuzzNormalize(data []byte) int { + f := fuzz.NewConsumer(data) + ignore := make([]v1alpha1.ResourceIgnoreDifferences, 0) + noOfIgnores, err := f.GetInt() + if err != nil { + return 0 + } + for i := 0; i < noOfIgnores%30; i++ { + ign := v1alpha1.ResourceIgnoreDifferences{} + err = f.GenerateStruct(&ign) + if err != nil { + return 0 + } + ignore = append(ignore, ign) + } + + overrides := make(map[string]v1alpha1.ResourceOverride) + err = f.FuzzMap(&overrides) + if err != nil { + return 0 + } + + unstructuredData, err := f.GetString() + if err != nil { + return 0 + } + un, err := UnstructuredForFuzzing(unstructuredData) + if err != nil { + return 0 + } + normalizer, err := NewIgnoreNormalizer(ignore, overrides) + if err != nil { + return 0 + } + _ = normalizer.Normalize(un) + return 1 +} diff --git a/projects/argo/project.yaml b/projects/argo/project.yaml new file mode 100644 index 000000000..e60b41d8d --- /dev/null +++ b/projects/argo/project.yaml @@ -0,0 +1,13 @@ +homepage: "https://argoproj.github.io/" +main_repo: "https://github.com/argoproj" +primary_contact: "terrytangyuan@gmail.com" +auto_ccs : + - "adam@adalogics.com" + - "david@adalogics.com" + - "errytangyuan@gmail.com" + - "jfischer@redhat.com " +language: go +fuzzing_engines: + - libfuzzer +sanitizers: + - address diff --git a/projects/argo/workflow_validation_fuzzer.go b/projects/argo/workflow_validation_fuzzer.go new file mode 100644 index 000000000..ffa642121 --- /dev/null +++ b/projects/argo/workflow_validation_fuzzer.go @@ -0,0 +1,27 @@ +package validate + +import ( + fuzz "github.com/AdaLogics/go-fuzz-headers" + wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" + fakewfclientset "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned/fake" + "github.com/argoproj/argo-workflows/v3/workflow/templateresolution" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var ( + wfClientsetFuzz = fakewfclientset.NewSimpleClientset() + wftmplGetterFuzz = templateresolution.WrapWorkflowTemplateInterface(wfClientsetFuzz.ArgoprojV1alpha1().WorkflowTemplates(metav1.NamespaceDefault)) + cwftmplGetterFuzz = templateresolution.WrapClusterWorkflowTemplateInterface(wfClientsetFuzz.ArgoprojV1alpha1().ClusterWorkflowTemplates()) +) + +func FuzzValidateWorkflow(data []byte) int { + f := fuzz.NewConsumer(data) + wf := &wfv1.Workflow{} + err := f.GenerateStruct(wf) + if err != nil { + return 0 + } + opts := ValidateOpts{} + _, _ = ValidateWorkflow(wftmplGetterFuzz, cwftmplGetterFuzz, wf, opts) + return 1 +}