1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "fmt" 19 "path/filepath" 20 "reflect" 21 "regexp" 22 "strconv" 23 "strings" 24 25 "github.com/google/blueprint/proptools" 26) 27 28// "neverallow" rules for the build system. 29// 30// This allows things which aren't related to the build system and are enforced 31// against assumptions, in progress code refactors, or policy to be expressed in a 32// straightforward away disjoint from implementations and tests which should 33// work regardless of these restrictions. 34// 35// A module is disallowed if all of the following are true: 36// - it is in one of the "In" paths 37// - it is not in one of the "NotIn" paths 38// - it has all "With" properties matched 39// - - values are matched in their entirety 40// - - nil is interpreted as an empty string 41// - - nested properties are separated with a '.' 42// - - if the property is a list, any of the values in the list being matches 43// counts as a match 44// - it has none of the "Without" properties matched (same rules as above) 45 46func registerNeverallowMutator(ctx RegisterMutatorsContext) { 47 ctx.BottomUp("neverallow", neverallowMutator) 48} 49 50var neverallows = []Rule{} 51 52func init() { 53 AddNeverAllowRules(createIncludeDirsRules()...) 54 AddNeverAllowRules(createTrebleRules()...) 55 AddNeverAllowRules(createJavaDeviceForHostRules()...) 56 AddNeverAllowRules(createCcSdkVariantRules()...) 57 AddNeverAllowRules(createUncompressDexRules()...) 58 AddNeverAllowRules(createInstallInRootAllowingRules()...) 59 AddNeverAllowRules(createProhibitFrameworkAccessRules()...) 60 AddNeverAllowRules(createCcStubsRule()) 61 AddNeverAllowRules(createProhibitHeaderOnlyRule()) 62 AddNeverAllowRules(createLimitNdkExportRule()...) 63 AddNeverAllowRules(createLimitDirgroupRule()...) 64 AddNeverAllowRules(createFilesystemIsAutoGeneratedRule()) 65 AddNeverAllowRules(createKotlinPluginRule()...) 66 AddNeverAllowRules(createPrebuiltEtcBpDefineRule()) 67 AddNeverAllowRules(createAutogenRroBpDefineRule()) 68} 69 70// Add a NeverAllow rule to the set of rules to apply. 71func AddNeverAllowRules(rules ...Rule) { 72 neverallows = append(neverallows, rules...) 73} 74 75var ( 76 neverallowNotInIncludeDir = []string{ 77 "art", 78 "art/libnativebridge", 79 "art/libnativeloader", 80 "libcore", 81 "libnativehelper", 82 "external/apache-harmony", 83 "external/apache-xml", 84 "external/boringssl", 85 "external/bouncycastle", 86 "external/conscrypt", 87 "external/icu", 88 "external/okhttp", 89 "external/vixl", 90 "external/wycheproof", 91 } 92 neverallowNoUseIncludeDir = []string{ 93 "frameworks/av/apex", 94 "frameworks/av/tools", 95 "frameworks/native/cmds", 96 "system/apex", 97 "system/bpf", 98 "system/gatekeeper", 99 "system/hwservicemanager", 100 "system/libbase", 101 "system/libfmq", 102 "system/libvintf", 103 } 104) 105 106func createIncludeDirsRules() []Rule { 107 rules := make([]Rule, 0, len(neverallowNotInIncludeDir)+len(neverallowNoUseIncludeDir)) 108 109 for _, path := range neverallowNotInIncludeDir { 110 rule := 111 NeverAllow(). 112 WithMatcher("include_dirs", StartsWith(path+"/")). 113 Because("include_dirs is deprecated, all usages of '" + path + "' have been migrated" + 114 " to use alternate mechanisms and so can no longer be used.") 115 116 rules = append(rules, rule) 117 } 118 119 for _, path := range neverallowNoUseIncludeDir { 120 rule := NeverAllow().In(path+"/").WithMatcher("include_dirs", isSetMatcherInstance). 121 Because("include_dirs is deprecated, all usages of them in '" + path + "' have been migrated" + 122 " to use alternate mechanisms and so can no longer be used.") 123 rules = append(rules, rule) 124 } 125 126 return rules 127} 128 129func createTrebleRules() []Rule { 130 return []Rule{ 131 NeverAllow(). 132 In("vendor", "device"). 133 With("vndk.enabled", "true"). 134 Without("vendor", "true"). 135 Without("product_specific", "true"). 136 Because("the VNDK can never contain a library that is device dependent."), 137 NeverAllow(). 138 With("vndk.enabled", "true"). 139 Without("vendor", "true"). 140 Without("owner", ""). 141 Because("a VNDK module can never have an owner."), 142 143 // TODO(b/67974785): always enforce the manifest 144 NeverAllow(). 145 Without("name", "libhidlbase-combined-impl"). 146 Without("name", "libhidlbase"). 147 With("product_variables.enforce_vintf_manifest.cflags", "*"). 148 Because("manifest enforcement should be independent of ."), 149 150 // TODO(b/67975799): vendor code should always use /vendor/bin/sh 151 NeverAllow(). 152 Without("name", "libc_bionic_ndk"). 153 With("product_variables.treble_linker_namespaces.cflags", "*"). 154 Because("nothing should care if linker namespaces are enabled or not"), 155 156 // Example: 157 // *NeverAllow().with("Srcs", "main.cpp")) 158 } 159} 160 161func createJavaDeviceForHostRules() []Rule { 162 javaDeviceForHostProjectsAllowedList := []string{ 163 "development/build", 164 "external/guava", 165 "external/kotlinx.coroutines", 166 "external/robolectric-shadows", 167 "external/robolectric", 168 "frameworks/base/ravenwood", 169 "frameworks/base/tools/hoststubgen", 170 "frameworks/layoutlib", 171 } 172 173 return []Rule{ 174 NeverAllow(). 175 NotIn(javaDeviceForHostProjectsAllowedList...). 176 ModuleType("java_device_for_host", "java_host_for_device"). 177 Because("java_device_for_host can only be used in allowed projects"), 178 } 179} 180 181func createCcSdkVariantRules() []Rule { 182 sdkVersionOnlyAllowedList := []string{ 183 // derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk. 184 // This sometimes works because the APEX modules that contain derive_sdk and 185 // derive_sdk_prefer32 suppress the platform installation rules, but fails when 186 // the APEX modules contain the SDK variant and the platform variant still exists. 187 "packages/modules/SdkExtensions/derive_sdk", 188 // These are for apps and shouldn't be used by non-SDK variant modules. 189 "prebuilts/ndk", 190 "frameworks/native/libs/binder/ndk", 191 "tools/test/graphicsbenchmark/apps/sample_app", 192 "tools/test/graphicsbenchmark/functional_tests/java", 193 "vendor/xts/gts-tests/hostsidetests/gamedevicecert/apps/javatests", 194 "external/libtextclassifier/native", 195 } 196 197 platformVariantPropertiesAllowedList := []string{ 198 // android_native_app_glue and libRSSupport use native_window.h but target old 199 // sdk versions (minimum and 9 respectively) where libnativewindow didn't exist, 200 // so they can't add libnativewindow to shared_libs to get the header directory 201 // for the platform variant. Allow them to use the platform variant 202 // property to set shared_libs. 203 "prebuilts/ndk", 204 "frameworks/rs", 205 } 206 207 return []Rule{ 208 NeverAllow(). 209 NotIn(sdkVersionOnlyAllowedList...). 210 WithMatcher("sdk_variant_only", isSetMatcherInstance). 211 Because("sdk_variant_only can only be used in allowed projects"), 212 NeverAllow(). 213 NotIn(platformVariantPropertiesAllowedList...). 214 WithMatcher("platform.shared_libs", isSetMatcherInstance). 215 Because("platform variant properties can only be used in allowed projects"), 216 } 217} 218 219func createCcStubsRule() Rule { 220 ccStubsImplementationInstallableProjectsAllowedList := []string{ 221 "packages/modules/Virtualization/libs/libvm_payload", 222 } 223 224 return NeverAllow(). 225 NotIn(ccStubsImplementationInstallableProjectsAllowedList...). 226 WithMatcher("stubs.implementation_installable", isSetMatcherInstance). 227 Because("implementation_installable can only be used in allowed projects.") 228} 229 230func createUncompressDexRules() []Rule { 231 return []Rule{ 232 NeverAllow(). 233 NotIn("art"). 234 WithMatcher("uncompress_dex", isSetMatcherInstance). 235 Because("uncompress_dex is only allowed for certain jars for test in art."), 236 } 237} 238 239func createInstallInRootAllowingRules() []Rule { 240 return []Rule{ 241 NeverAllow(). 242 Without("name", "init_first_stage_defaults"). 243 Without("name", "init_first_stage"). 244 Without("name", "init_first_stage.microdroid"). 245 Without("name", "librecovery_ui_ext"). 246 With("install_in_root", "true"). 247 NotModuleType("prebuilt_root"). 248 NotModuleType("prebuilt_vendor"). 249 NotModuleType("prebuilt_sbin"). 250 NotModuleType("prebuilt_system"). 251 NotModuleType("prebuilt_first_stage_ramdisk"). 252 NotModuleType("prebuilt_res"). 253 Because("install_in_root is only for init_first_stage or librecovery_ui_ext."), 254 } 255} 256 257func createProhibitFrameworkAccessRules() []Rule { 258 return []Rule{ 259 NeverAllow(). 260 With("libs", "framework"). 261 WithoutMatcher("sdk_version", Regexp("(core_.*|^$)")). 262 Because("framework can't be used when building against SDK"), 263 } 264} 265 266func createProhibitHeaderOnlyRule() Rule { 267 return NeverAllow(). 268 Without("name", "framework-minus-apex-headers"). 269 With("headers_only", "true"). 270 Because("headers_only can only be used for generating framework-minus-apex headers for non-updatable modules") 271} 272 273func createLimitNdkExportRule() []Rule { 274 reason := "If the headers you're trying to export are meant to be a part of the NDK, they should be exposed by an ndk_headers module. If the headers shouldn't be a part of the NDK, the headers should instead be exposed from a separate `cc_library_headers` which consumers depend on." 275 // DO NOT ADD HERE - please consult danalbert@ 276 // b/357711733 277 return []Rule{ 278 NeverAllow(). 279 NotIn("frameworks/native/libs/binder/ndk"). 280 ModuleType("ndk_library"). 281 WithMatcher("export_header_libs", isSetMatcherInstance).Because(reason), 282 NeverAllow().ModuleType("ndk_library").WithMatcher("export_generated_headers", isSetMatcherInstance).Because(reason), 283 NeverAllow().ModuleType("ndk_library").WithMatcher("export_include_dirs", isSetMatcherInstance).Because(reason), 284 NeverAllow().ModuleType("ndk_library").WithMatcher("export_shared_lib_headers", isSetMatcherInstance).Because(reason), 285 NeverAllow().ModuleType("ndk_library").WithMatcher("export_static_lib_headers", isSetMatcherInstance).Because(reason), 286 } 287} 288 289func createLimitDirgroupRule() []Rule { 290 reason := "dirgroup module and dir_srcs / keep_gendir property of genrule is allowed only to Trusty build rule." 291 return []Rule{ 292 NeverAllow(). 293 ModuleType("dirgroup"). 294 WithMatcher("visibility", NotInList([]string{"//trusty/vendor/google/aosp/scripts"})).Because(reason), 295 NeverAllow(). 296 ModuleType("dirgroup"). 297 Without("visibility", "//trusty/vendor/google/aosp/scripts").Because(reason), 298 NeverAllow(). 299 ModuleType("genrule"). 300 Without("name", "trusty-arm64.lk.elf.gen"). 301 Without("name", "trusty-arm64-virt-test-debug.lk.elf.gen"). 302 Without("name", "trusty-x86_64.lk.elf.gen"). 303 Without("name", "trusty-x86_64-test.lk.elf.gen"). 304 WithMatcher("dir_srcs", isSetMatcherInstance).Because(reason), 305 NeverAllow(). 306 ModuleType("genrule"). 307 Without("name", "trusty-arm64.lk.elf.gen"). 308 Without("name", "trusty-arm64-virt-test-debug.lk.elf.gen"). 309 Without("name", "trusty-x86_64.lk.elf.gen"). 310 Without("name", "trusty-x86_64-test.lk.elf.gen"). 311 With("keep_gendir", "true").Because(reason), 312 } 313} 314 315func createFilesystemIsAutoGeneratedRule() Rule { 316 return NeverAllow(). 317 NotIn("build/soong/fsgen"). 318 ModuleType("filesystem", "android_system_image"). 319 WithMatcher("is_auto_generated", isSetMatcherInstance). 320 Because("is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory") 321} 322 323func createKotlinPluginRule() []Rule { 324 kotlinPluginProjectsAllowedList := []string{ 325 // TODO: Migrate compose plugin to the bundled compiler plugin 326 // Actual path prebuilts/sdk/current/androidx/m2repository/androidx/compose/compiler/compiler-hosted 327 "prebuilts/sdk/current/androidx", 328 "external/kotlinc", 329 } 330 331 return []Rule{ 332 NeverAllow(). 333 NotIn(kotlinPluginProjectsAllowedList...). 334 ModuleType("kotlin_plugin"). 335 Because("kotlin_plugin can only be used in allowed projects"), 336 } 337} 338 339// These module types are introduced to convert PRODUCT_COPY_FILES to Soong, 340// and is only intended to be used by filesystem_creator. 341func createPrebuiltEtcBpDefineRule() Rule { 342 return NeverAllow(). 343 ModuleType( 344 "prebuilt_usr_srec", 345 "prebuilt_priv_app", 346 "prebuilt_rfs", 347 "prebuilt_framework", 348 "prebuilt_wlc_upt", 349 "prebuilt_odm", 350 "prebuilt_vendor_dlkm", 351 "prebuilt_bt_firmware", 352 "prebuilt_tvservice", 353 "prebuilt_optee", 354 "prebuilt_tvconfig", 355 "prebuilt_vendor", 356 "prebuilt_sbin", 357 "prebuilt_system", 358 "prebuilt_first_stage_ramdisk", 359 ). 360 DefinedInBpFile(). 361 Because("module type not allowed to be defined in bp file") 362} 363 364func createAutogenRroBpDefineRule() Rule { 365 return NeverAllow(). 366 ModuleType( 367 "autogen_runtime_resource_overlay", 368 ). 369 DefinedInBpFile(). 370 Because("Module type will be autogenerated by soong. Use runtime_resource_overlay instead") 371} 372 373func neverallowMutator(ctx BottomUpMutatorContext) { 374 m, ok := ctx.Module().(Module) 375 if !ok { 376 return 377 } 378 379 dir := ctx.ModuleDir() + "/" 380 properties := m.GetProperties() 381 382 osClass := ctx.Module().Target().Os.Class 383 384 for _, r := range neverallowRules(ctx.Config()) { 385 n := r.(*rule) 386 if !n.appliesToPath(dir) { 387 continue 388 } 389 390 if !n.appliesToModuleType(ctx.ModuleType()) { 391 continue 392 } 393 394 if !n.appliesToProperties(ctx, properties) { 395 continue 396 } 397 398 if !n.appliesToOsClass(osClass) { 399 continue 400 } 401 402 if !n.appliesToDirectDeps(ctx) { 403 continue 404 } 405 406 if !n.appliesToBpDefinedModule(ctx) { 407 continue 408 } 409 410 ctx.ModuleErrorf("violates " + n.String()) 411 } 412} 413 414type ValueMatcher interface { 415 Test(string) bool 416 String() string 417} 418 419type equalMatcher struct { 420 expected string 421} 422 423func (m *equalMatcher) Test(value string) bool { 424 return m.expected == value 425} 426 427func (m *equalMatcher) String() string { 428 return "=" + m.expected 429} 430 431type anyMatcher struct { 432} 433 434func (m *anyMatcher) Test(value string) bool { 435 return true 436} 437 438func (m *anyMatcher) String() string { 439 return "=*" 440} 441 442var anyMatcherInstance = &anyMatcher{} 443 444type startsWithMatcher struct { 445 prefix string 446} 447 448func (m *startsWithMatcher) Test(value string) bool { 449 return strings.HasPrefix(value, m.prefix) 450} 451 452func (m *startsWithMatcher) String() string { 453 return ".starts-with(" + m.prefix + ")" 454} 455 456type regexMatcher struct { 457 re *regexp.Regexp 458} 459 460func (m *regexMatcher) Test(value string) bool { 461 return m.re.MatchString(value) 462} 463 464func (m *regexMatcher) String() string { 465 return ".regexp(" + m.re.String() + ")" 466} 467 468type notInListMatcher struct { 469 allowed []string 470} 471 472func (m *notInListMatcher) Test(value string) bool { 473 return !InList(value, m.allowed) 474} 475 476func (m *notInListMatcher) String() string { 477 return ".not-in-list(" + strings.Join(m.allowed, ",") + ")" 478} 479 480type isSetMatcher struct{} 481 482func (m *isSetMatcher) Test(value string) bool { 483 return value != "" 484} 485 486func (m *isSetMatcher) String() string { 487 return ".is-set" 488} 489 490var isSetMatcherInstance = &isSetMatcher{} 491 492type ruleProperty struct { 493 fields []string // e.x.: Vndk.Enabled 494 matcher ValueMatcher 495} 496 497func (r *ruleProperty) String() string { 498 return fmt.Sprintf("%q matches: %s", strings.Join(r.fields, "."), r.matcher) 499} 500 501type ruleProperties []ruleProperty 502 503func (r ruleProperties) String() string { 504 var s []string 505 for _, r := range r { 506 s = append(s, r.String()) 507 } 508 return strings.Join(s, " ") 509} 510 511// A NeverAllow rule. 512type Rule interface { 513 In(path ...string) Rule 514 515 NotIn(path ...string) Rule 516 517 InDirectDeps(deps ...string) Rule 518 519 WithOsClass(osClasses ...OsClass) Rule 520 521 ModuleType(types ...string) Rule 522 523 NotModuleType(types ...string) Rule 524 525 With(properties, value string) Rule 526 527 WithMatcher(properties string, matcher ValueMatcher) Rule 528 529 Without(properties, value string) Rule 530 531 WithoutMatcher(properties string, matcher ValueMatcher) Rule 532 533 DefinedInBpFile() Rule 534 535 Because(reason string) Rule 536} 537 538type rule struct { 539 // User string for why this is a thing. 540 reason string 541 542 paths []string 543 unlessPaths []string 544 545 directDeps map[string]bool 546 547 osClasses []OsClass 548 549 moduleTypes []string 550 unlessModuleTypes []string 551 552 props ruleProperties 553 unlessProps ruleProperties 554 555 onlyBootclasspathJar bool 556 557 definedInBp bool 558} 559 560// Create a new NeverAllow rule. 561func NeverAllow() Rule { 562 return &rule{directDeps: make(map[string]bool)} 563} 564 565// In adds path(s) where this rule applies. 566func (r *rule) In(path ...string) Rule { 567 r.paths = append(r.paths, cleanPaths(path)...) 568 return r 569} 570 571// NotIn adds path(s) to that this rule does not apply to. 572func (r *rule) NotIn(path ...string) Rule { 573 r.unlessPaths = append(r.unlessPaths, cleanPaths(path)...) 574 return r 575} 576 577// InDirectDeps adds dep(s) that are not allowed with this rule. 578func (r *rule) InDirectDeps(deps ...string) Rule { 579 for _, d := range deps { 580 r.directDeps[d] = true 581 } 582 return r 583} 584 585// WithOsClass adds osClass(es) that this rule applies to. 586func (r *rule) WithOsClass(osClasses ...OsClass) Rule { 587 r.osClasses = append(r.osClasses, osClasses...) 588 return r 589} 590 591// ModuleType adds type(s) that this rule applies to. 592func (r *rule) ModuleType(types ...string) Rule { 593 r.moduleTypes = append(r.moduleTypes, types...) 594 return r 595} 596 597// NotModuleType adds type(s) that this rule does not apply to.. 598func (r *rule) NotModuleType(types ...string) Rule { 599 r.unlessModuleTypes = append(r.unlessModuleTypes, types...) 600 return r 601} 602 603// With specifies property/value combinations that are restricted for this rule. 604func (r *rule) With(properties, value string) Rule { 605 return r.WithMatcher(properties, selectMatcher(value)) 606} 607 608// WithMatcher specifies property/matcher combinations that are restricted for this rule. 609func (r *rule) WithMatcher(properties string, matcher ValueMatcher) Rule { 610 r.props = append(r.props, ruleProperty{ 611 fields: fieldNamesForProperties(properties), 612 matcher: matcher, 613 }) 614 return r 615} 616 617// Without specifies property/value combinations that this rule does not apply to. 618func (r *rule) Without(properties, value string) Rule { 619 return r.WithoutMatcher(properties, selectMatcher(value)) 620} 621 622// Without specifies property/matcher combinations that this rule does not apply to. 623func (r *rule) WithoutMatcher(properties string, matcher ValueMatcher) Rule { 624 r.unlessProps = append(r.unlessProps, ruleProperty{ 625 fields: fieldNamesForProperties(properties), 626 matcher: matcher, 627 }) 628 return r 629} 630 631// DefinedInBpFile specifies that this rule applies to modules that are defined 632// in bp files, and does not apply to modules that are auto generated by other modules. 633func (r *rule) DefinedInBpFile() Rule { 634 r.definedInBp = true 635 return r 636} 637 638func selectMatcher(expected string) ValueMatcher { 639 if expected == "*" { 640 return anyMatcherInstance 641 } 642 return &equalMatcher{expected: expected} 643} 644 645// Because specifies a reason for this rule. 646func (r *rule) Because(reason string) Rule { 647 r.reason = reason 648 return r 649} 650 651func (r *rule) String() string { 652 s := []string{"neverallow requirements. Not allowed:"} 653 if len(r.paths) > 0 { 654 s = append(s, fmt.Sprintf("in dirs: %q", r.paths)) 655 } 656 if len(r.moduleTypes) > 0 { 657 s = append(s, fmt.Sprintf("module types: %q", r.moduleTypes)) 658 } 659 if len(r.props) > 0 { 660 s = append(s, fmt.Sprintf("properties matching: %s", r.props)) 661 } 662 if len(r.directDeps) > 0 { 663 s = append(s, fmt.Sprintf("dep(s): %q", SortedKeys(r.directDeps))) 664 } 665 if len(r.osClasses) > 0 { 666 s = append(s, fmt.Sprintf("os class(es): %q", r.osClasses)) 667 } 668 if len(r.unlessPaths) > 0 { 669 s = append(s, fmt.Sprintf("EXCEPT in dirs: %q", r.unlessPaths)) 670 } 671 if len(r.unlessModuleTypes) > 0 { 672 s = append(s, fmt.Sprintf("EXCEPT module types: %q", r.unlessModuleTypes)) 673 } 674 if len(r.unlessProps) > 0 { 675 s = append(s, fmt.Sprintf("EXCEPT properties matching: %q", r.unlessProps)) 676 } 677 if len(r.reason) != 0 { 678 s = append(s, " which is restricted because "+r.reason) 679 } 680 if len(s) == 1 { 681 s[0] = "neverallow requirements (empty)" 682 } 683 return strings.Join(s, "\n\t") 684} 685 686func (r *rule) appliesToPath(dir string) bool { 687 includePath := len(r.paths) == 0 || HasAnyPrefix(dir, r.paths) 688 excludePath := HasAnyPrefix(dir, r.unlessPaths) 689 return includePath && !excludePath 690} 691 692func (r *rule) appliesToDirectDeps(ctx BottomUpMutatorContext) bool { 693 if len(r.directDeps) == 0 { 694 return true 695 } 696 697 matches := false 698 ctx.VisitDirectDeps(func(m Module) { 699 if !matches { 700 name := ctx.OtherModuleName(m) 701 matches = r.directDeps[name] 702 } 703 }) 704 705 return matches 706} 707 708func (r *rule) appliesToOsClass(osClass OsClass) bool { 709 if len(r.osClasses) == 0 { 710 return true 711 } 712 713 for _, c := range r.osClasses { 714 if c == osClass { 715 return true 716 } 717 } 718 719 return false 720} 721 722func (r *rule) appliesToModuleType(moduleType string) bool { 723 // Remove prefix for auto-generated modules 724 moduleType = strings.TrimSuffix(moduleType, "__loadHookModule") 725 moduleType = strings.TrimSuffix(moduleType, "__bottomUpMutatorModule") 726 return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes) 727} 728 729func (r *rule) appliesToProperties(ctx BottomUpMutatorContext, properties []interface{}) bool { 730 includeProps := hasAllProperties(ctx, properties, r.props) 731 excludeProps := hasAnyProperty(ctx, properties, r.unlessProps) 732 return includeProps && !excludeProps 733} 734 735func (r *rule) appliesToBpDefinedModule(ctx BottomUpMutatorContext) bool { 736 if !r.definedInBp { 737 return true 738 } 739 return !ctx.OtherModuleIsAutoGenerated(ctx.Module()) == r.definedInBp 740} 741 742func StartsWith(prefix string) ValueMatcher { 743 return &startsWithMatcher{prefix} 744} 745 746func Regexp(re string) ValueMatcher { 747 r, err := regexp.Compile(re) 748 if err != nil { 749 panic(err) 750 } 751 return ®exMatcher{r} 752} 753 754func NotInList(allowed []string) ValueMatcher { 755 return ¬InListMatcher{allowed} 756} 757 758// assorted utils 759 760func cleanPaths(paths []string) []string { 761 res := make([]string, len(paths)) 762 for i, v := range paths { 763 res[i] = filepath.Clean(v) + "/" 764 } 765 return res 766} 767 768func fieldNamesForProperties(propertyNames string) []string { 769 names := strings.Split(propertyNames, ".") 770 for i, v := range names { 771 names[i] = proptools.FieldNameForProperty(v) 772 } 773 return names 774} 775 776func hasAnyProperty(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool { 777 for _, v := range props { 778 if hasProperty(ctx, properties, v) { 779 return true 780 } 781 } 782 return false 783} 784 785func hasAllProperties(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool { 786 for _, v := range props { 787 if !hasProperty(ctx, properties, v) { 788 return false 789 } 790 } 791 return true 792} 793 794func hasProperty(ctx BottomUpMutatorContext, properties []interface{}, prop ruleProperty) bool { 795 for _, propertyStruct := range properties { 796 propertiesValue := reflect.ValueOf(propertyStruct).Elem() 797 for _, v := range prop.fields { 798 if !propertiesValue.IsValid() { 799 break 800 } 801 propertiesValue = propertiesValue.FieldByName(v) 802 } 803 if !propertiesValue.IsValid() { 804 continue 805 } 806 807 check := func(value string) bool { 808 return prop.matcher.Test(value) 809 } 810 811 if matchValue(ctx, propertiesValue, check) { 812 return true 813 } 814 } 815 return false 816} 817 818func matchValue(ctx BottomUpMutatorContext, value reflect.Value, check func(string) bool) bool { 819 if !value.IsValid() { 820 return false 821 } 822 823 if value.Kind() == reflect.Ptr { 824 if value.IsNil() { 825 return check("") 826 } 827 value = value.Elem() 828 } 829 830 switch v := value.Interface().(type) { 831 case string: 832 return check(v) 833 case bool: 834 return check(strconv.FormatBool(v)) 835 case int: 836 return check(strconv.FormatInt((int64)(v), 10)) 837 case []string: 838 for _, v := range v { 839 if check(v) { 840 return true 841 } 842 } 843 return false 844 case proptools.Configurable[string]: 845 return check(v.GetOrDefault(ctx, "")) 846 case proptools.Configurable[bool]: 847 return check(strconv.FormatBool(v.GetOrDefault(ctx, false))) 848 case proptools.Configurable[[]string]: 849 for _, v := range v.GetOrDefault(ctx, nil) { 850 if check(v) { 851 return true 852 } 853 } 854 return false 855 } 856 857 panic("Can't handle type: " + value.Kind().String()) 858} 859 860var neverallowRulesKey = NewOnceKey("neverallowRules") 861 862func neverallowRules(config Config) []Rule { 863 return config.Once(neverallowRulesKey, func() interface{} { 864 // No test rules were set by setTestNeverallowRules, use the global rules 865 return neverallows 866 }).([]Rule) 867} 868 869// Overrides the default neverallow rules for the supplied config. 870// 871// For testing only. 872func setTestNeverallowRules(config Config, testRules []Rule) { 873 config.Once(neverallowRulesKey, func() interface{} { return testRules }) 874} 875 876// Prepares for a test by setting neverallow rules and enabling the mutator. 877// 878// If the supplied rules are nil then the default rules are used. 879func PrepareForTestWithNeverallowRules(testRules []Rule) FixturePreparer { 880 return GroupFixturePreparers( 881 FixtureModifyConfig(func(config Config) { 882 if testRules != nil { 883 setTestNeverallowRules(config, testRules) 884 } 885 }), 886 FixtureRegisterWithContext(func(ctx RegistrationContext) { 887 ctx.PostDepsMutators(registerNeverallowMutator) 888 }), 889 ) 890} 891