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 }