operator/controllers/execution/scans/scan_reconciler.go
package scancontrollers import ( "context" "errors" "fmt" "os" "path/filepath" "strings" "time" executionv1 "github.com/secureCodeBox/secureCodeBox-v2/operator/apis/execution/v1" util "github.com/secureCodeBox/secureCodeBox-v2/operator/utils" batch "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" resource "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client") Method `ScanReconciler.startScan` has 72 lines of code (exceeds 50 allowed). Consider refactoring.
Method `ScanReconciler.startScan` has 11 return statements (exceeds 4 allowed).func (r *ScanReconciler) startScan(scan *executionv1.Scan) error { ctx := context.Background() namespacedName := fmt.Sprintf("%s/%s", scan.Namespace, scan.Name) log := r.Log.WithValues("scan_init", namespacedName) jobs, err := r.getJobsForScan(scan, client.MatchingLabels{"securecodebox.io/job-type": "scanner"}) if err != nil { return err } if len(jobs.Items) > 0 { log.V(8).Info("Job already exists. Doesn't need to be created.") return nil } // Add s3 storage finalizer to scan if !containsString(scan.ObjectMeta.Finalizers, s3StorageFinalizer) { scan.ObjectMeta.Finalizers = append(scan.ObjectMeta.Finalizers, s3StorageFinalizer) if err := r.Update(context.Background(), scan); err != nil { return err } } // get the ScanType for the scan var scanType executionv1.ScanType if err := r.Get(ctx, types.NamespacedName{Name: scan.Spec.ScanType, Namespace: scan.Namespace}, &scanType); err != nil { log.V(7).Info("Unable to fetch ScanType") scan.Status.State = "Errored" scan.Status.ErrorDescription = fmt.Sprintf("Configured ScanType '%s' not found in '%s' namespace. You'll likely need to deploy the ScanType.", scan.Spec.ScanType, scan.Namespace) if err := r.Status().Update(ctx, scan); err != nil { r.Log.Error(err, "unable to update Scan status") return err } return fmt.Errorf("No ScanType of type '%s' found", scan.Spec.ScanType) } log.Info("Matching ScanType Found", "ScanType", scanType.Name) rules := []rbacv1.PolicyRule{ { APIGroups: []string{""}, Resources: []string{"pods"}, Verbs: []string{"get"}, }, } r.ensureServiceAccountExists( scan.Namespace, "lurcher", "Lurcher is used to extract results from secureCodeBox Scans. It needs rights to get and watch the status of pods to see when the scans have finished.", rules, ) job, err := r.constructJobForScan(scan, &scanType) if err != nil { log.Error(err, "unable to create job object ScanType") return err } log.V(7).Info("Constructed Job object", "job args", strings.Join(job.Spec.Template.Spec.Containers[0].Args, ", ")) if err := r.Create(ctx, job); err != nil { log.Error(err, "unable to create Job for Scan", "job", job) return err } scan.Status.State = "Scanning" scan.Status.RawResultType = scanType.Spec.ExtractResults.Type scan.Status.RawResultFile = filepath.Base(scanType.Spec.ExtractResults.Location) findingsDownloadURL, err := r.PresignedGetURL(scan.UID, "findings.json", 7*24*time.Hour) if err != nil { r.Log.Error(err, "Could not get presigned url from s3 or compatible storage provider") return err } scan.Status.FindingDownloadLink = findingsDownloadURL rawResultDownloadURL, err := r.PresignedGetURL(scan.UID, scan.Status.RawResultFile, 7*24*time.Hour) if err != nil { return err } scan.Status.RawResultDownloadLink = rawResultDownloadURL if err := r.Status().Update(ctx, scan); err != nil { log.Error(err, "unable to update Scan status") return err } log.V(1).Info("created Job for Scan", "job", job) return nil} // Checking if scan has completedfunc (r *ScanReconciler) checkIfScanIsCompleted(scan *executionv1.Scan) error { ctx := context.Background() status, err := r.checkIfJobIsCompleted(scan, client.MatchingLabels{"securecodebox.io/job-type": "scanner"}) if err != nil { return err } switch status { case completed: r.Log.V(7).Info("Scan is completed") scan.Status.State = "ScanCompleted" if err := r.Status().Update(ctx, scan); err != nil { r.Log.Error(err, "unable to update Scan status") return err } case failed: scan.Status.State = "Errored" scan.Status.ErrorDescription = "Failed to run the Scan Container, check k8s Job and its logs for more details" if err := r.Status().Update(ctx, scan); err != nil { r.Log.Error(err, "unable to update Scan status") return err } } // Either Incomplete or Unknown, nothing we can do, other then giving it some more time... return nil} Method `ScanReconciler.constructJobForScan` has 133 lines of code (exceeds 50 allowed). Consider refactoring.func (r *ScanReconciler) constructJobForScan(scan *executionv1.Scan, scanType *executionv1.ScanType) (*batch.Job, error) { filename := filepath.Base(scanType.Spec.ExtractResults.Location) resultUploadURL, err := r.PresignedPutURL(scan.UID, filename, defaultPresignDuration) if err != nil { r.Log.Error(err, "Could not get presigned url from s3 or compatible storage provider") return nil, err } if len(scanType.Spec.JobTemplate.Spec.Template.Spec.Containers) < 1 { return nil, errors.New("ScanType must at least contain one container in which the scanner is running") } labels := scan.ObjectMeta.DeepCopy().Labels if labels == nil { labels = make(map[string]string) } labels["securecodebox.io/job-type"] = "scanner" job := &batch.Job{ ObjectMeta: metav1.ObjectMeta{ Labels: labels, GenerateName: util.TruncateName(fmt.Sprintf("scan-%s", scan.Name)), Namespace: scan.Namespace, }, Spec: *scanType.Spec.JobTemplate.Spec.DeepCopy(), } podAnnotations := scanType.Spec.JobTemplate.DeepCopy().Annotations if podAnnotations == nil { podAnnotations = make(map[string]string) } podAnnotations["securecodebox.io/job-type"] = "scanner" // Ensuring that istio doesn't inject a sidecar proxy. podAnnotations["sidecar.istio.io/inject"] = "false" job.Spec.Template.Annotations = podAnnotations job.Spec.Template.Spec.ServiceAccountName = "lurcher" // merging volume definition from ScanType (if existing) with standard results volume if job.Spec.Template.Spec.Containers[0].VolumeMounts == nil || len(job.Spec.Template.Spec.Containers[0].VolumeMounts) == 0 { job.Spec.Template.Spec.Volumes = []corev1.Volume{} } job.Spec.Template.Spec.Volumes = append(job.Spec.Template.Spec.Volumes, corev1.Volume{ Name: "scan-results", VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }) // merging volume mounts (for the primary scanner container) from ScanType (if existing) with standard results volume mount if job.Spec.Template.Spec.Containers[0].VolumeMounts == nil || len(job.Spec.Template.Spec.Containers[0].VolumeMounts) == 0 { job.Spec.Template.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{} } job.Spec.Template.Spec.Containers[0].VolumeMounts = append( job.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{ Name: "scan-results", MountPath: "/home/securecodebox/", }, ) // Get lurcher image config from env lurcherImage := os.Getenv("LURCHER_IMAGE") if lurcherImage == "" { lurcherImage = "securecodebox/lurcher:latest" } lurcherPullPolicyRaw := os.Getenv("LURCHER_PULL_POLICY") var lurcherPullPolicy corev1.PullPolicy switch lurcherPullPolicyRaw { case "Always": lurcherPullPolicy = corev1.PullAlways case "IfNotPresent": lurcherPullPolicy = corev1.PullIfNotPresent case "Never": lurcherPullPolicy = corev1.PullNever case "": lurcherPullPolicy = corev1.PullAlways default: return nil, fmt.Errorf("Unknown imagePull Policy for lurcher: %s", lurcherPullPolicyRaw) } falsePointer := false truePointer := true lurcherSidecar := &corev1.Container{ Name: "lurcher", Image: lurcherImage, ImagePullPolicy: lurcherPullPolicy, Args: []string{ "--container", job.Spec.Template.Spec.Containers[0].Name, "--file", scanType.Spec.ExtractResults.Location, "--url", resultUploadURL, }, Env: []corev1.EnvVar{ { Name: "NAMESPACE", ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "metadata.namespace", }, }, }, }, Resources: corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("20m"), corev1.ResourceMemory: resource.MustParse("20Mi"), }, Limits: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), corev1.ResourceMemory: resource.MustParse("100Mi"), }, }, VolumeMounts: []corev1.VolumeMount{ { Name: "scan-results", MountPath: "/home/securecodebox/", ReadOnly: true, }, }, SecurityContext: &corev1.SecurityContext{ RunAsNonRoot: &truePointer, AllowPrivilegeEscalation: &falsePointer, ReadOnlyRootFilesystem: &truePointer, Privileged: &falsePointer, Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{"all"}, }, }, } job.Spec.Template.Spec.Containers = append(job.Spec.Template.Spec.Containers, *lurcherSidecar) if err := ctrl.SetControllerReference(scan, job, r.Scheme); err != nil { return nil, err } command := append( scanType.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Command, scan.Spec.Parameters..., ) // Merge Env from ScanTemplate with Env defined in scan job.Spec.Template.Spec.Containers[0].Env = append( job.Spec.Template.Spec.Containers[0].Env, scan.Spec.Env..., ) // Using command over args job.Spec.Template.Spec.Containers[0].Command = command job.Spec.Template.Spec.Containers[0].Args = nil return job, nil}