github.com/datreeio/datree@v1.9.22-rc/pkg/jsonSchemaValidator/extensions/customKeyRule89.go (about)

     1  // This file defines a custom key to implement the logic for the rule:
     2  // https://hub.datree.io/built-in-rules/ensure-hostpath-mounts-readonly
     3  
     4  package jsonSchemaValidator
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/itchyny/gojq"
    10  	"github.com/santhosh-tekuri/jsonschema/v5"
    11  )
    12  
    13  type CustomKeyRule89Compiler struct{}
    14  
    15  type CustomKeyRule89Schema map[string]interface{}
    16  
    17  var CustomKeyRule89 = jsonschema.MustCompileString("customKeyRule89.json", `{
    18  	"properties" : {
    19  		"customKeyRule89": {
    20  			"type": "string"
    21  		}
    22  	}
    23  }`)
    24  
    25  func (CustomKeyRule89Compiler) Compile(ctx jsonschema.CompilerContext, m map[string]interface{}) (jsonschema.ExtSchema, error) {
    26  	if customKeyRule89, ok := m["customKeyRule89"]; ok {
    27  		customKeyRule89Str, validStr := customKeyRule89.(map[string]interface{})
    28  		if !validStr {
    29  			return nil, fmt.Errorf("customKeyRule89 must be a string")
    30  		}
    31  		return CustomKeyRule89Schema(customKeyRule89Str), nil
    32  	}
    33  	return nil, nil
    34  }
    35  
    36  func (s CustomKeyRule89Schema) Validate(ctx jsonschema.ValidationContext, dataValue interface{}) error {
    37  	namesOfVolumesWithHostPath := getNamesOfVolumesWithHostPath(dataValue)
    38  	namesOfVolumeMountsWithoutReadonly := getNamesOfVolumeMountsWithoutReadonly(dataValue)
    39  
    40  	for _, nameOfVolumeMountWithoutReadonly := range namesOfVolumeMountsWithoutReadonly {
    41  		for _, nameOfVolumeWithHostPath := range namesOfVolumesWithHostPath {
    42  			if nameOfVolumeMountWithoutReadonly == nameOfVolumeWithHostPath {
    43  				return ctx.Error("volumeMounts", "a container is using a hostPath volume without setting it to read-only")
    44  			}
    45  		}
    46  	}
    47  	return nil
    48  }
    49  
    50  func getNamesOfVolumesWithHostPath(dataValue interface{}) []string {
    51  	var hostPathVolumes []string
    52  
    53  	// Get all volumes with hostPath
    54  	hostPathVolumeNameQuery, _ := gojq.Parse(".volumes[] | select(.hostPath != null) | .name")
    55  	hostPathVolumeNameIter := hostPathVolumeNameQuery.Run(dataValue)
    56  	for {
    57  		volumeName, ok := hostPathVolumeNameIter.Next()
    58  		if !ok {
    59  			break
    60  		}
    61  		if _, ok := volumeName.(error); ok {
    62  			break
    63  		}
    64  
    65  		hostPathVolumes = append(hostPathVolumes, volumeName.(string))
    66  	}
    67  	return hostPathVolumes
    68  }
    69  
    70  func getNamesOfVolumeMountsWithoutReadonly(dataValue interface{}) []string {
    71  	var namesOfVolumeMountsWithoutReadonly []string
    72  
    73  	// Get all volumeMounts without readOnly
    74  	volumeMountsNameQuery, _ := gojq.Parse(".containers[] | .volumeMounts[] | select((.readOnly == null) or (.readOnly == false)) | .name")
    75  	volumeMountsNameIter := volumeMountsNameQuery.Run(dataValue)
    76  	for {
    77  		volumeMountName, ok := volumeMountsNameIter.Next()
    78  		if !ok || volumeMountName == nil {
    79  			break
    80  		}
    81  		if _, ok := volumeMountName.(error); ok {
    82  			break
    83  		}
    84  
    85  		namesOfVolumeMountsWithoutReadonly = append(namesOfVolumeMountsWithoutReadonly, volumeMountName.(string))
    86  	}
    87  
    88  	return namesOfVolumeMountsWithoutReadonly
    89  }