github.com/zntrio/harp/v2@v2.0.9/pkg/bundle/ruleset/engine/cel/ext/package.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package ext 19 20 import ( 21 "reflect" 22 "strings" 23 24 "github.com/gobwas/glob" 25 "github.com/google/cel-go/cel" 26 "github.com/google/cel-go/common/types" 27 "github.com/google/cel-go/common/types/ref" 28 29 bundlev1 "github.com/zntrio/harp/v2/api/gen/go/harp/bundle/v1" 30 csov1 "github.com/zntrio/harp/v2/pkg/cso/v1" 31 htypes "github.com/zntrio/harp/v2/pkg/sdk/types" 32 ) 33 34 // Packages exported package operations. 35 func Packages() cel.EnvOption { 36 return cel.Lib(packageLib{}) 37 } 38 39 type packageLib struct{} 40 41 func (packageLib) CompileOptions() []cel.EnvOption { 42 reg, err := types.NewRegistry( 43 &bundlev1.KV{}, 44 ) 45 if err != nil { 46 panic(err) 47 } 48 49 return []cel.EnvOption{ 50 cel.Variable("p", harpPackageObjectType), 51 cel.Function( 52 "match_label", 53 cel.MemberOverload("package_match_label_string", []*cel.Type{harpPackageObjectType, cel.StringType}, cel.BoolType, 54 cel.BinaryBinding(celPackageMatchLabel), 55 ), 56 cel.MemberOverload("package_match_label_string_string", []*cel.Type{harpPackageObjectType, cel.StringType, cel.StringType}, cel.BoolType, 57 cel.FunctionBinding(celPackageMatchLabelValue), 58 ), 59 ), 60 cel.Function( 61 "match_annotation", 62 cel.MemberOverload("package_match_annotation_string", []*cel.Type{harpPackageObjectType, cel.StringType}, cel.BoolType, 63 cel.BinaryBinding(celPackageMatchAnnotation), 64 ), 65 cel.MemberOverload("package_match_annotation_string_string", []*cel.Type{harpPackageObjectType, cel.StringType, cel.StringType}, cel.BoolType, 66 cel.FunctionBinding(celPackageMatchAnnotationValue), 67 ), 68 ), 69 cel.Function( 70 "match_path", 71 cel.MemberOverload("package_match_path_string", []*cel.Type{harpPackageObjectType, cel.StringType}, cel.BoolType, 72 cel.BinaryBinding(celPackageMatchPath), 73 ), 74 ), 75 cel.Function( 76 "match_secret", 77 cel.MemberOverload("package_match_secret_string", []*cel.Type{harpPackageObjectType, cel.StringType}, cel.BoolType, 78 cel.BinaryBinding(celPackageMatchSecret), 79 ), 80 ), 81 cel.Function( 82 "has_secret", 83 cel.MemberOverload("package_has_secret_string", []*cel.Type{harpPackageObjectType, cel.StringType}, cel.BoolType, 84 cel.BinaryBinding(celPackageHasSecret), 85 ), 86 ), 87 cel.Function( 88 "without_secret", 89 cel.MemberOverload("package_without_secret_string", []*cel.Type{harpPackageObjectType}, cel.BoolType, 90 cel.UnaryBinding(celPackageWithoutSecret), 91 ), 92 ), 93 cel.Function( 94 "has_all_secrets", 95 cel.MemberOverload("package_has_all_secrets_string", []*cel.Type{harpPackageObjectType, cel.ListType(cel.StringType)}, cel.BoolType, 96 cel.BinaryBinding(celPackageHasAllSecrets), 97 ), 98 ), 99 cel.Function( 100 "is_cso_compliant", 101 cel.MemberOverload("package_is_cso_compliant", []*cel.Type{harpPackageObjectType}, cel.BoolType, 102 cel.UnaryBinding(celPackageIsCSOCompliant), 103 ), 104 ), 105 cel.Function( 106 "secret", 107 cel.MemberOverload("package_secret_string", []*cel.Type{harpPackageObjectType, cel.StringType}, harpKVObjectType, 108 cel.BinaryBinding(celPackageGetSecret(reg)), 109 ), 110 ), 111 } 112 } 113 114 func (packageLib) ProgramOptions() []cel.ProgramOption { 115 return []cel.ProgramOption{} 116 } 117 118 // ----------------------------------------------------------------------------- 119 120 func celPackageMatchLabel(lhs, rhs ref.Val) ref.Val { 121 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 122 p, ok := x.(*bundlev1.Package) 123 if !ok { 124 return types.Bool(false) 125 } 126 127 patternTyped, ok := rhs.(types.String) 128 if !ok { 129 return types.Bool(false) 130 } 131 132 pattern, ok := patternTyped.Value().(string) 133 if !ok { 134 return types.Bool(false) 135 } 136 137 m := glob.MustCompile(pattern) 138 for k := range p.Labels { 139 if m.Match(k) { 140 return types.Bool(true) 141 } 142 } 143 144 return types.Bool(false) 145 } 146 147 func celPackageMatchLabelValue(values ...ref.Val) ref.Val { 148 if len(values) != 3 { 149 return types.Bool(false) 150 } 151 152 lhs := values[0] 153 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 154 p, ok := x.(*bundlev1.Package) 155 if !ok { 156 return types.Bool(false) 157 } 158 159 keyPatternTyped, ok := values[1].(types.String) 160 if !ok { 161 return types.Bool(false) 162 } 163 164 keyPattern, ok := keyPatternTyped.Value().(string) 165 if !ok { 166 return types.Bool(false) 167 } 168 169 valuePatternTyped, ok := values[2].(types.String) 170 if !ok { 171 return types.Bool(false) 172 } 173 174 valuePattern, ok := valuePatternTyped.Value().(string) 175 if !ok { 176 return types.Bool(false) 177 } 178 179 km := glob.MustCompile(keyPattern) 180 vm := glob.MustCompile(valuePattern) 181 182 for k, v := range p.Labels { 183 if km.Match(k) && vm.Match(v) { 184 return types.Bool(true) 185 } 186 } 187 188 return types.Bool(false) 189 } 190 191 func celPackageMatchAnnotation(lhs, rhs ref.Val) ref.Val { 192 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 193 p, ok := x.(*bundlev1.Package) 194 if !ok { 195 return types.Bool(false) 196 } 197 198 patternTyped, ok := rhs.(types.String) 199 if !ok { 200 return types.Bool(false) 201 } 202 203 pattern, ok := patternTyped.Value().(string) 204 if !ok { 205 return types.Bool(false) 206 } 207 208 m := glob.MustCompile(pattern) 209 for k := range p.Annotations { 210 if m.Match(k) { 211 return types.Bool(true) 212 } 213 } 214 215 return types.Bool(false) 216 } 217 218 func celPackageMatchAnnotationValue(values ...ref.Val) ref.Val { 219 if len(values) != 3 { 220 return types.Bool(false) 221 } 222 223 lhs := values[0] 224 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 225 p, ok := x.(*bundlev1.Package) 226 if !ok { 227 return types.Bool(false) 228 } 229 230 keyPatternTyped, ok := values[1].(types.String) 231 if !ok { 232 return types.Bool(false) 233 } 234 235 keyPattern, ok := keyPatternTyped.Value().(string) 236 if !ok { 237 return types.Bool(false) 238 } 239 240 valuePatternTyped, ok := values[2].(types.String) 241 if !ok { 242 return types.Bool(false) 243 } 244 245 valuePattern, ok := valuePatternTyped.Value().(string) 246 if !ok { 247 return types.Bool(false) 248 } 249 250 km := glob.MustCompile(keyPattern) 251 vm := glob.MustCompile(valuePattern) 252 253 for k, v := range p.Annotations { 254 if km.Match(k) && vm.Match(v) { 255 return types.Bool(true) 256 } 257 } 258 259 return types.Bool(false) 260 } 261 262 func celPackageMatchPath(lhs, rhs ref.Val) ref.Val { 263 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 264 p, ok := x.(*bundlev1.Package) 265 if !ok { 266 return types.Bool(false) 267 } 268 269 pathTyped, ok := rhs.(types.String) 270 if !ok { 271 return types.Bool(false) 272 } 273 274 path, ok := pathTyped.Value().(string) 275 if !ok { 276 return types.Bool(false) 277 } 278 279 return types.Bool(glob.MustCompile(path).Match(p.Name)) 280 } 281 282 func celPackageMatchSecret(lhs, rhs ref.Val) ref.Val { 283 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 284 p, ok := x.(*bundlev1.Package) 285 if !ok { 286 return types.Bool(false) 287 } 288 289 secretTyped, ok := rhs.(types.String) 290 if !ok { 291 return types.Bool(false) 292 } 293 294 secretName, ok := secretTyped.Value().(string) 295 if !ok { 296 return types.Bool(false) 297 } 298 299 // No secret data 300 if p.Secrets == nil || p.Secrets.Data == nil || len(p.Secrets.Data) == 0 { 301 return types.Bool(false) 302 } 303 304 m := glob.MustCompile(secretName) 305 306 // Look for secret name 307 for _, s := range p.Secrets.Data { 308 if m.Match(s.Key) { 309 return types.Bool(true) 310 } 311 } 312 313 return types.Bool(false) 314 } 315 316 func celPackageHasSecret(lhs, rhs ref.Val) ref.Val { 317 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 318 p, ok := x.(*bundlev1.Package) 319 if !ok { 320 return types.Bool(false) 321 } 322 323 secretTyped, ok := rhs.(types.String) 324 if !ok { 325 return types.Bool(false) 326 } 327 328 secretName, ok := secretTyped.Value().(string) 329 if !ok { 330 return types.Bool(false) 331 } 332 333 // No secret data 334 if p.Secrets == nil || p.Secrets.Data == nil || len(p.Secrets.Data) == 0 { 335 return types.Bool(false) 336 } 337 338 // Look for secret name 339 for _, k := range p.Secrets.Data { 340 if strings.EqualFold(k.Key, secretName) { 341 return types.Bool(true) 342 } 343 } 344 345 return types.Bool(false) 346 } 347 348 func celPackageWithoutSecret(value ref.Val) ref.Val { 349 x, _ := value.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 350 p, ok := x.(*bundlev1.Package) 351 if !ok { 352 return types.Bool(false) 353 } 354 355 // Look for secret name 356 if p.Secrets == nil || len(p.Secrets.Data) == 0 { 357 return types.Bool(true) 358 } 359 360 return types.Bool(false) 361 } 362 363 func celPackageHasAllSecrets(lhs, rhs ref.Val) ref.Val { 364 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 365 p, ok := x.(*bundlev1.Package) 366 if !ok { 367 return types.Bool(false) 368 } 369 370 secretsTyped, _ := rhs.ConvertToNative(reflect.TypeOf([]string{})) 371 secretNames, ok := secretsTyped.([]string) 372 if !ok { 373 return types.Bool(false) 374 } 375 376 // No secret data 377 if p.Secrets == nil || p.Secrets.Data == nil || len(p.Secrets.Data) == 0 { 378 return types.Bool(false) 379 } 380 381 sa := htypes.StringArray(secretNames) 382 383 secretMap := map[string]*bundlev1.KV{} 384 for _, k := range p.Secrets.Data { 385 if !sa.Contains(k.Key) { 386 return types.Bool(false) 387 } 388 secretMap[k.Key] = k 389 } 390 391 // Look for secret name 392 for _, k := range secretNames { 393 if _, ok := secretMap[k]; !ok { 394 return types.Bool(false) 395 } 396 } 397 398 return types.Bool(true) 399 } 400 401 func celPackageIsCSOCompliant(lhs ref.Val) ref.Val { 402 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 403 p, ok := x.(*bundlev1.Package) 404 if !ok { 405 return types.Bool(false) 406 } 407 408 if err := csov1.Validate(p.Name); err != nil { 409 return types.Bool(false) 410 } 411 412 return types.Bool(true) 413 } 414 415 func celPackageGetSecret(reg ref.TypeAdapter) func(lhs, rhs ref.Val) ref.Val { 416 return func(lhs, rhs ref.Val) ref.Val { 417 x, _ := lhs.ConvertToNative(reflect.TypeOf(&bundlev1.Package{})) 418 p, ok := x.(*bundlev1.Package) 419 if !ok { 420 return types.Bool(false) 421 } 422 423 secretTyped, ok := rhs.(types.String) 424 if !ok { 425 return types.Bool(false) 426 } 427 428 secretName, ok := secretTyped.Value().(string) 429 if !ok { 430 return types.Bool(false) 431 } 432 433 // No secret data 434 if p.Secrets == nil || p.Secrets.Data == nil || len(p.Secrets.Data) == 0 { 435 return types.Bool(false) 436 } 437 438 // Look for secret name 439 for _, k := range p.Secrets.Data { 440 if strings.EqualFold(k.Key, secretName) { 441 return reg.NativeToValue(k) 442 } 443 } 444 445 return nil 446 } 447 }