xref: /aosp_15_r20/build/soong/android/neverallow_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright 2018 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	"regexp"
19	"testing"
20
21	"github.com/google/blueprint"
22)
23
24var neverallowTests = []struct {
25	// The name of the test.
26	name string
27
28	// Optional test specific rules. If specified then they are used instead of the default rules.
29	rules []Rule
30
31	// Additional contents to add to the virtual filesystem used by the tests.
32	fs MockFS
33
34	// The expected error patterns. If empty then no errors are expected, otherwise each error
35	// reported must be matched by at least one of these patterns. A pattern matches if the error
36	// message contains the pattern. A pattern does not have to match the whole error message.
37	expectedErrors []string
38}{
39	// Test General Functionality
40
41	// in direct deps tests
42	{
43		name: "not_allowed_in_direct_deps",
44		rules: []Rule{
45			NeverAllow().InDirectDeps("not_allowed_in_direct_deps"),
46		},
47		fs: map[string][]byte{
48			"top/Android.bp": []byte(`
49				cc_library {
50					name: "not_allowed_in_direct_deps",
51				}`),
52			"other/Android.bp": []byte(`
53				cc_library {
54					name: "libother",
55					static_libs: ["not_allowed_in_direct_deps"],
56				}`),
57		},
58		expectedErrors: []string{
59			regexp.QuoteMeta("module \"libother\": violates neverallow requirements. Not allowed:\n\tdep(s): [\"not_allowed_in_direct_deps\"]"),
60		},
61	},
62	{
63		name: "multiple constraints",
64		rules: []Rule{
65			NeverAllow().
66				InDirectDeps("not_allowed_in_direct_deps").
67				In("other").
68				ModuleType("cc_library").
69				NotIn("top").
70				NotModuleType("cc_binary"),
71		},
72		fs: map[string][]byte{
73			"top/Android.bp": []byte(`
74				cc_library {
75					name: "not_allowed_in_direct_deps",
76				}`),
77			"other/Android.bp": []byte(`
78				cc_library {
79					name: "libother",
80					static_libs: ["not_allowed_in_direct_deps"],
81				}`),
82		},
83		expectedErrors: []string{
84			regexp.QuoteMeta(`module "libother": violates neverallow requirements. Not allowed:
85	in dirs: ["other/"]
86	module types: ["cc_library"]
87	dep(s): ["not_allowed_in_direct_deps"]
88	EXCEPT in dirs: ["top/"]
89	EXCEPT module types: ["cc_binary"]`),
90		},
91	},
92
93	// Test android specific rules
94
95	// include_dir rule tests
96	{
97		name: "include_dir not allowed to reference art",
98		fs: map[string][]byte{
99			"other/Android.bp": []byte(`
100				cc_library {
101					name: "libother",
102					include_dirs: ["art/libdexfile/include"],
103				}`),
104		},
105		expectedErrors: []string{
106			"all usages of 'art' have been migrated",
107		},
108	},
109	{
110		name: "include_dir not allowed to reference art",
111		fs: map[string][]byte{
112			"system/libfmq/Android.bp": []byte(`
113				cc_library {
114					name: "libother",
115					include_dirs: ["any/random/file"],
116				}`),
117		},
118		expectedErrors: []string{
119			"all usages of them in 'system/libfmq' have been migrated",
120		},
121	},
122	{
123		name: "include_dir can work",
124		fs: map[string][]byte{
125			"other/Android.bp": []byte(`
126				cc_library {
127					name: "libother",
128					include_dirs: ["another/include"],
129				}`),
130		},
131	},
132	// Treble rule tests
133	{
134		name: "no vndk.enabled under vendor directory",
135		fs: map[string][]byte{
136			"vendor/Android.bp": []byte(`
137				cc_library {
138					name: "libvndk",
139					vendor_available: true,
140					vndk: {
141						enabled: true,
142					},
143				}`),
144		},
145		expectedErrors: []string{
146			"VNDK can never contain a library that is device dependent",
147		},
148	},
149	{
150		name: "no vndk.enabled under device directory",
151		fs: map[string][]byte{
152			"device/Android.bp": []byte(`
153				cc_library {
154					name: "libvndk",
155					vendor_available: true,
156					vndk: {
157						enabled: true,
158					},
159				}`),
160		},
161		expectedErrors: []string{
162			"VNDK can never contain a library that is device dependent",
163		},
164	},
165	{
166		name: "vndk-ext under vendor or device directory",
167		fs: map[string][]byte{
168			"device/Android.bp": []byte(`
169				cc_library {
170					name: "libvndk1_ext",
171					vendor: true,
172					vndk: {
173						enabled: true,
174					},
175				}`),
176			"vendor/Android.bp": []byte(`
177				cc_library {
178					name: "libvndk2_ext",
179					vendor: true,
180					vndk: {
181						enabled: true,
182					},
183				}`),
184		},
185	},
186
187	{
188		name: "no enforce_vintf_manifest.cflags",
189		fs: map[string][]byte{
190			"Android.bp": []byte(`
191				cc_library {
192					name: "libexample",
193					product_variables: {
194						enforce_vintf_manifest: {
195							cflags: ["-DSHOULD_NOT_EXIST"],
196						},
197					},
198				}`),
199		},
200		expectedErrors: []string{
201			"manifest enforcement should be independent",
202		},
203	},
204
205	{
206		name: "no treble_linker_namespaces.cflags",
207		fs: map[string][]byte{
208			"Android.bp": []byte(`
209				cc_library {
210					name: "libexample",
211					product_variables: {
212						treble_linker_namespaces: {
213							cflags: ["-DSHOULD_NOT_EXIST"],
214						},
215					},
216				}`),
217		},
218		expectedErrors: []string{
219			"nothing should care if linker namespaces are enabled or not",
220		},
221	},
222	{
223		name: "libc_bionic_ndk treble_linker_namespaces.cflags",
224		fs: map[string][]byte{
225			"Android.bp": []byte(`
226				cc_library {
227					name: "libc_bionic_ndk",
228					product_variables: {
229						treble_linker_namespaces: {
230							cflags: ["-DSHOULD_NOT_EXIST"],
231						},
232					},
233				}`),
234		},
235	},
236	{
237		name: "java_device_for_host",
238		fs: map[string][]byte{
239			"Android.bp": []byte(`
240				java_device_for_host {
241					name: "device_for_host",
242					libs: ["core-libart"],
243				}`),
244		},
245		expectedErrors: []string{
246			"java_device_for_host can only be used in allowed projects",
247		},
248	},
249	// CC sdk rule tests
250	{
251		name: `"sdk_variant_only" outside allowed list`,
252		fs: map[string][]byte{
253			"Android.bp": []byte(`
254				cc_library {
255					name: "outside_allowed_list",
256					sdk_version: "current",
257					sdk_variant_only: true,
258				}`),
259		},
260		expectedErrors: []string{
261			`module "outside_allowed_list": violates neverallow`,
262		},
263	},
264	{
265		name: `"sdk_variant_only: false" outside allowed list`,
266		fs: map[string][]byte{
267			"Android.bp": []byte(`
268				cc_library {
269					name: "outside_allowed_list",
270					sdk_version: "current",
271					sdk_variant_only: false,
272				}`),
273		},
274		expectedErrors: []string{
275			`module "outside_allowed_list": violates neverallow`,
276		},
277	},
278	{
279		name: `"platform" outside allowed list`,
280		fs: map[string][]byte{
281			"Android.bp": []byte(`
282				cc_library {
283					name: "outside_allowed_list",
284					platform: {
285						shared_libs: ["libfoo"],
286					},
287				}`),
288		},
289		expectedErrors: []string{
290			`module "outside_allowed_list": violates neverallow`,
291		},
292	},
293	{
294		name: "uncompress_dex inside art",
295		fs: map[string][]byte{
296			"art/Android.bp": []byte(`
297				java_library {
298					name: "inside_art_libraries",
299					uncompress_dex: true,
300				}`),
301		},
302	},
303	{
304		name: "uncompress_dex outside art",
305		fs: map[string][]byte{
306			"other/Android.bp": []byte(`
307				java_library {
308					name: "outside_art_libraries",
309					uncompress_dex: true,
310				}`),
311		},
312		expectedErrors: []string{
313			"module \"outside_art_libraries\": violates neverallow",
314		},
315	},
316	// Tests for the rule prohibiting the use of framework
317	{
318		name: "prohibit framework",
319		fs: map[string][]byte{
320			"Android.bp": []byte(`
321				java_library {
322					name: "foo",
323					libs: ["framework"],
324					sdk_version: "current",
325				}`),
326		},
327		expectedErrors: []string{
328			"framework can't be used when building against SDK",
329		},
330	},
331	// Test for the rule restricting use of implementation_installable
332	{
333		name: `"implementation_installable" outside allowed list`,
334		fs: map[string][]byte{
335			"Android.bp": []byte(`
336				cc_library {
337					name: "outside_allowed_list",
338					stubs: {
339                                                implementation_installable: true,
340					},
341				}`),
342		},
343		expectedErrors: []string{
344			`module "outside_allowed_list": violates neverallow`,
345		},
346	},
347	// Test for only allowing headers_only for framework-minus-apex-headers
348	{
349		name: `"headers_only" outside framework-minus-apex-headers modules`,
350		fs: map[string][]byte{
351			"a/b/Android.bp": []byte(`
352				java_library {
353					name: "baz",
354					headers_only: true,
355				}
356			`),
357		},
358		expectedErrors: []string{
359			`headers_only can only be used for generating framework-minus-apex headers for non-updatable modules`,
360		},
361	},
362	// Test for the rule restricting use of is_auto_generated
363	{
364		name: `"is_auto_generated" outside allowed directory`,
365		fs: map[string][]byte{
366			"a/b/Android.bp": []byte(`
367				filesystem {
368					name: "baaz",
369					is_auto_generated: true,
370				}
371			`),
372		},
373		expectedErrors: []string{
374			`is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory`,
375		},
376	},
377	// Test for the rule restricting use of prebuilt_* module
378	{
379		name: `"prebuilt_usr_srec" defined in Android.bp file`,
380		fs: map[string][]byte{
381			"a/b/Android.bp": []byte(`
382				prebuilt_usr_srec {
383					name: "foo",
384				}
385			`),
386		},
387		expectedErrors: []string{
388			`module type not allowed to be defined in bp file`,
389		},
390	},
391}
392
393var prepareForNeverAllowTest = GroupFixturePreparers(
394	FixtureRegisterWithContext(func(ctx RegistrationContext) {
395		ctx.RegisterModuleType("cc_library", newMockCcLibraryModule)
396		ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
397		ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
398		ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
399		ctx.RegisterModuleType("filesystem", newMockFilesystemModule)
400		ctx.RegisterModuleType("prebuilt_usr_srec", newMockPrebuiltUsrSrecModule)
401	}),
402)
403
404func TestNeverallow(t *testing.T) {
405	for _, test := range neverallowTests {
406		t.Run(test.name, func(t *testing.T) {
407			GroupFixturePreparers(
408				prepareForNeverAllowTest,
409				PrepareForTestWithNeverallowRules(test.rules),
410				test.fs.AddToFixture(),
411			).
412				ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
413				RunTest(t)
414		})
415	}
416}
417
418type mockCcLibraryProperties struct {
419	Include_dirs     []string
420	Vendor_available *bool
421	Static_libs      []string
422	Sdk_version      *string
423	Sdk_variant_only *bool
424
425	Vndk struct {
426		Enabled                *bool
427		Support_system_process *bool
428		Extends                *string
429	}
430
431	Product_variables struct {
432		Enforce_vintf_manifest struct {
433			Cflags []string
434		}
435
436		Treble_linker_namespaces struct {
437			Cflags []string
438		}
439	}
440
441	Platform struct {
442		Shared_libs []string
443	}
444
445	Stubs struct {
446		Implementation_installable *bool
447	}
448}
449
450type mockCcLibraryModule struct {
451	ModuleBase
452	properties mockCcLibraryProperties
453}
454
455func newMockCcLibraryModule() Module {
456	m := &mockCcLibraryModule{}
457	m.AddProperties(&m.properties)
458	InitAndroidModule(m)
459	return m
460}
461
462type neverallowTestDependencyTag struct {
463	blueprint.BaseDependencyTag
464	name string
465}
466
467var staticDepTag = neverallowTestDependencyTag{name: "static"}
468
469func (c *mockCcLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
470	for _, lib := range c.properties.Static_libs {
471		ctx.AddDependency(ctx.Module(), staticDepTag, lib)
472	}
473}
474
475func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
476}
477
478type mockJavaLibraryProperties struct {
479	Libs                []string
480	Sdk_version         *string
481	Uncompress_dex      *bool
482	Exclude_static_libs []string
483	Headers_only        *bool
484}
485
486type mockJavaLibraryModule struct {
487	ModuleBase
488	properties mockJavaLibraryProperties
489}
490
491func newMockJavaLibraryModule() Module {
492	m := &mockJavaLibraryModule{}
493	m.AddProperties(&m.properties)
494	InitAndroidModule(m)
495	return m
496}
497
498func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
499}
500
501type mockPrebuiltUsrSrecModule struct {
502	ModuleBase
503}
504
505func (p *mockPrebuiltUsrSrecModule) GenerateAndroidBuildActions(ModuleContext) {
506}
507
508func newMockPrebuiltUsrSrecModule() Module {
509	m := &mockPrebuiltUsrSrecModule{}
510	InitAndroidModule(m)
511	return m
512}
513