secureCodeBox/secureCodeBox-v2-alpha

View on GitHub
operator/controllers/execution/scans/parse_reconciler.go

Summary

Maintainability
B
5 hrs
Test Coverage
package scancontrollers
 
import (
"context"
"fmt"
"strings"
 
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.startParser` has 140 lines of code (exceeds 50 allowed). Consider refactoring.
Method `ScanReconciler.startParser` has 10 return statements (exceeds 4 allowed).
func (r *ScanReconciler) startParser(scan *executionv1.Scan) error {
ctx := context.Background()
namespacedName := fmt.Sprintf("%s/%s", scan.Namespace, scan.Name)
log := r.Log.WithValues("scan_parse", namespacedName)
 
jobs, err := r.getJobsForScan(scan, client.MatchingLabels{"securecodebox.io/job-type": "parser"})
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
}
 
parseType := scan.Status.RawResultType
 
// get the scan template for the scan
var parseDefinition executionv1.ParseDefinition
if err := r.Get(ctx, types.NamespacedName{Name: parseType, Namespace: scan.Namespace}, &parseDefinition); err != nil {
log.V(7).Info("Unable to fetch ParseDefinition")
 
scan.Status.State = "Errored"
scan.Status.ErrorDescription = fmt.Sprintf("No ParseDefinition for ResultType '%s' found in Scans Namespace.", parseType)
if err := r.Status().Update(ctx, scan); err != nil {
r.Log.Error(err, "unable to update Scan status")
return err
}
 
return fmt.Errorf("No ParseDefinition of type '%s' found", parseType)
}
log.Info("Matching ParseDefinition Found", "ParseDefinition", parseType)
 
findingsUploadURL, err := r.PresignedPutURL(scan.UID, "findings.json", defaultPresignDuration)
if err != nil {
r.Log.Error(err, "Could not get presigned url from s3 or compatible storage provider")
return err
}
rawResultDownloadURL, err := r.PresignedGetURL(scan.UID, scan.Status.RawResultFile, defaultPresignDuration)
if err != nil {
return err
}
 
rules := []rbacv1.PolicyRule{
{
APIGroups: []string{"execution.securecodebox.io"},
Resources: []string{"scans/status"},
Verbs: []string{"get", "patch"},
},
}
r.ensureServiceAccountExists(
scan.Namespace,
"parser",
"Parser need to access the status of Scans to update how many findings have been identified",
rules,
)
 
labels := scan.ObjectMeta.DeepCopy().Labels
if labels == nil {
labels = make(map[string]string)
}
labels["securecodebox.io/job-type"] = "parser"
automountServiceAccountToken := true
var backOffLimit int32 = 3
truePointer := true
falsePointer := false
job := &batch.Job{
ObjectMeta: metav1.ObjectMeta{
Annotations: make(map[string]string),
GenerateName: util.TruncateName(fmt.Sprintf("parse-%s", scan.Name)),
Namespace: scan.Namespace,
Labels: labels,
},
Spec: batch.JobSpec{
BackoffLimit: &backOffLimit,
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
"auto-discovery.securecodebox.io/ignore": "true",
"sidecar.istio.io/inject": "false",
},
},
Spec: corev1.PodSpec{
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: "parser",
ImagePullSecrets: parseDefinition.Spec.ImagePullSecrets,
Containers: []corev1.Container{
{
Name: "parser",
Image: parseDefinition.Spec.Image,
Env: []corev1.EnvVar{
{
Name: "NAMESPACE",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: "metadata.namespace",
},
},
},
{
Name: "SCAN_NAME",
Value: scan.Name,
},
},
Args: []string{
rawResultDownloadURL,
findingsUploadURL,
},
ImagePullPolicy: "Always",
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("200m"),
corev1.ResourceMemory: resource.MustParse("100Mi"),
},
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("400m"),
corev1.ResourceMemory: resource.MustParse("200Mi"),
},
},
SecurityContext: &corev1.SecurityContext{
RunAsNonRoot: &truePointer,
AllowPrivilegeEscalation: &falsePointer,
ReadOnlyRootFilesystem: &truePointer,
Privileged: &falsePointer,
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"all"},
},
},
},
},
AutomountServiceAccountToken: &automountServiceAccountToken,
},
},
TTLSecondsAfterFinished: nil,
},
}
 
if err := ctrl.SetControllerReference(scan, job, r.Scheme); err != nil {
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 Parser", "job", job)
return err
}
 
scan.Status.State = "Parsing"
if err := r.Status().Update(ctx, scan); err != nil {
log.Error(err, "unable to update Scan status")
return err
}
 
log.V(1).Info("created Parse Job for Scan", "job", job)
return nil
}
 
func (r *ScanReconciler) checkIfParsingIsCompleted(scan *executionv1.Scan) error {
ctx := context.Background()
 
status, err := r.checkIfJobIsCompleted(scan, client.MatchingLabels{"securecodebox.io/job-type": "parser"})
if err != nil {
return err
}
 
switch status {
case completed:
r.Log.V(7).Info("Parsing is completed")
scan.Status.State = "ParseCompleted"
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 Parser. This is likely a Bug, we would like to know about. Please open up a Issue on GitHub."
if err := r.Status().Update(ctx, scan); err != nil {
r.Log.Error(err, "unable to update Scan status")
return err
}
}
 
return nil
}