xref: /aosp_15_r20/build/make/tools/compliance/policy_policy.go (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker// Copyright 2021 Google LLC
2*9e94795aSAndroid Build Coastguard Worker//
3*9e94795aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*9e94795aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*9e94795aSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*9e94795aSAndroid Build Coastguard Worker//
7*9e94795aSAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*9e94795aSAndroid Build Coastguard Worker//
9*9e94795aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*9e94795aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*9e94795aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9e94795aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*9e94795aSAndroid Build Coastguard Worker// limitations under the License.
14*9e94795aSAndroid Build Coastguard Worker
15*9e94795aSAndroid Build Coastguard Workerpackage compliance
16*9e94795aSAndroid Build Coastguard Worker
17*9e94795aSAndroid Build Coastguard Workerimport (
18*9e94795aSAndroid Build Coastguard Worker	"regexp"
19*9e94795aSAndroid Build Coastguard Worker	"strings"
20*9e94795aSAndroid Build Coastguard Worker)
21*9e94795aSAndroid Build Coastguard Worker
22*9e94795aSAndroid Build Coastguard Workervar (
23*9e94795aSAndroid Build Coastguard Worker	// RecognizedAnnotations identifies the set of annotations that have
24*9e94795aSAndroid Build Coastguard Worker	// meaning for compliance policy.
25*9e94795aSAndroid Build Coastguard Worker	RecognizedAnnotations = map[string]string{
26*9e94795aSAndroid Build Coastguard Worker		// used in readgraph.go to avoid creating 1000's of copies of the below 3 strings.
27*9e94795aSAndroid Build Coastguard Worker		"static":    "static",
28*9e94795aSAndroid Build Coastguard Worker		"dynamic":   "dynamic",
29*9e94795aSAndroid Build Coastguard Worker		"toolchain": "toolchain",
30*9e94795aSAndroid Build Coastguard Worker	}
31*9e94795aSAndroid Build Coastguard Worker
32*9e94795aSAndroid Build Coastguard Worker	// safePathPrefixes maps the path prefixes presumed not to contain any
33*9e94795aSAndroid Build Coastguard Worker	// proprietary or confidential pathnames to whether to strip the prefix
34*9e94795aSAndroid Build Coastguard Worker	// from the path when used as the library name for notices.
35*9e94795aSAndroid Build Coastguard Worker	safePathPrefixes = []safePathPrefixesType{
36*9e94795aSAndroid Build Coastguard Worker		{"external/", true},
37*9e94795aSAndroid Build Coastguard Worker		{"art/", false},
38*9e94795aSAndroid Build Coastguard Worker		{"build/", false},
39*9e94795aSAndroid Build Coastguard Worker		{"cts/", false},
40*9e94795aSAndroid Build Coastguard Worker		{"dalvik/", false},
41*9e94795aSAndroid Build Coastguard Worker		{"developers/", false},
42*9e94795aSAndroid Build Coastguard Worker		{"development/", false},
43*9e94795aSAndroid Build Coastguard Worker		{"frameworks/", false},
44*9e94795aSAndroid Build Coastguard Worker		{"packages/", true},
45*9e94795aSAndroid Build Coastguard Worker		{"prebuilts/module_sdk/", true},
46*9e94795aSAndroid Build Coastguard Worker		{"prebuilts/", false},
47*9e94795aSAndroid Build Coastguard Worker		{"sdk/", false},
48*9e94795aSAndroid Build Coastguard Worker		{"system/", false},
49*9e94795aSAndroid Build Coastguard Worker		{"test/", false},
50*9e94795aSAndroid Build Coastguard Worker		{"toolchain/", false},
51*9e94795aSAndroid Build Coastguard Worker		{"tools/", false},
52*9e94795aSAndroid Build Coastguard Worker	}
53*9e94795aSAndroid Build Coastguard Worker
54*9e94795aSAndroid Build Coastguard Worker	// safePrebuiltPrefixes maps the regular expression to match a prebuilt
55*9e94795aSAndroid Build Coastguard Worker	// containing the path of a safe prefix to the safe prefix.
56*9e94795aSAndroid Build Coastguard Worker	safePrebuiltPrefixes []safePrebuiltPrefixesType
57*9e94795aSAndroid Build Coastguard Worker
58*9e94795aSAndroid Build Coastguard Worker	// ImpliesUnencumbered lists the condition names representing an author attempt to disclaim copyright.
59*9e94795aSAndroid Build Coastguard Worker	ImpliesUnencumbered = LicenseConditionSet(UnencumberedCondition)
60*9e94795aSAndroid Build Coastguard Worker
61*9e94795aSAndroid Build Coastguard Worker	// ImpliesPermissive lists the condition names representing copyrighted but "licensed without policy requirements".
62*9e94795aSAndroid Build Coastguard Worker	ImpliesPermissive = LicenseConditionSet(PermissiveCondition)
63*9e94795aSAndroid Build Coastguard Worker
64*9e94795aSAndroid Build Coastguard Worker	// ImpliesNotice lists the condition names implying a notice or attribution policy.
65*9e94795aSAndroid Build Coastguard Worker	ImpliesNotice = LicenseConditionSet(UnencumberedCondition | PermissiveCondition | NoticeCondition | ReciprocalCondition |
66*9e94795aSAndroid Build Coastguard Worker		RestrictedCondition | WeaklyRestrictedCondition | ProprietaryCondition | ByExceptionOnlyCondition)
67*9e94795aSAndroid Build Coastguard Worker
68*9e94795aSAndroid Build Coastguard Worker	// ImpliesReciprocal lists the condition names implying a local source-sharing policy.
69*9e94795aSAndroid Build Coastguard Worker	ImpliesReciprocal = LicenseConditionSet(ReciprocalCondition)
70*9e94795aSAndroid Build Coastguard Worker
71*9e94795aSAndroid Build Coastguard Worker	// Restricted lists the condition names implying an infectious source-sharing policy.
72*9e94795aSAndroid Build Coastguard Worker	ImpliesRestricted = LicenseConditionSet(RestrictedCondition | WeaklyRestrictedCondition)
73*9e94795aSAndroid Build Coastguard Worker
74*9e94795aSAndroid Build Coastguard Worker	// ImpliesProprietary lists the condition names implying a confidentiality policy.
75*9e94795aSAndroid Build Coastguard Worker	ImpliesProprietary = LicenseConditionSet(ProprietaryCondition)
76*9e94795aSAndroid Build Coastguard Worker
77*9e94795aSAndroid Build Coastguard Worker	// ImpliesByExceptionOnly lists the condition names implying a policy for "license review and approval before use".
78*9e94795aSAndroid Build Coastguard Worker	ImpliesByExceptionOnly = LicenseConditionSet(ProprietaryCondition | ByExceptionOnlyCondition)
79*9e94795aSAndroid Build Coastguard Worker
80*9e94795aSAndroid Build Coastguard Worker	// ImpliesPrivate lists the condition names implying a source-code privacy policy.
81*9e94795aSAndroid Build Coastguard Worker	ImpliesPrivate = LicenseConditionSet(ProprietaryCondition)
82*9e94795aSAndroid Build Coastguard Worker
83*9e94795aSAndroid Build Coastguard Worker	// ImpliesShared lists the condition names implying a source-code sharing policy.
84*9e94795aSAndroid Build Coastguard Worker	ImpliesShared = LicenseConditionSet(ReciprocalCondition | RestrictedCondition | WeaklyRestrictedCondition)
85*9e94795aSAndroid Build Coastguard Worker)
86*9e94795aSAndroid Build Coastguard Worker
87*9e94795aSAndroid Build Coastguard Workertype safePathPrefixesType struct {
88*9e94795aSAndroid Build Coastguard Worker	prefix string
89*9e94795aSAndroid Build Coastguard Worker	strip  bool
90*9e94795aSAndroid Build Coastguard Worker}
91*9e94795aSAndroid Build Coastguard Worker
92*9e94795aSAndroid Build Coastguard Workertype safePrebuiltPrefixesType struct {
93*9e94795aSAndroid Build Coastguard Worker	safePathPrefixesType
94*9e94795aSAndroid Build Coastguard Worker	re *regexp.Regexp
95*9e94795aSAndroid Build Coastguard Worker}
96*9e94795aSAndroid Build Coastguard Worker
97*9e94795aSAndroid Build Coastguard Workervar (
98*9e94795aSAndroid Build Coastguard Worker	anyLgpl      = regexp.MustCompile(`^SPDX-license-identifier-LGPL.*`)
99*9e94795aSAndroid Build Coastguard Worker	versionedGpl = regexp.MustCompile(`^SPDX-license-identifier-GPL-\p{N}.*`)
100*9e94795aSAndroid Build Coastguard Worker	genericGpl   = regexp.MustCompile(`^SPDX-license-identifier-GPL$`)
101*9e94795aSAndroid Build Coastguard Worker	ccBySa       = regexp.MustCompile(`^SPDX-license-identifier-CC-BY.*-SA.*`)
102*9e94795aSAndroid Build Coastguard Worker)
103*9e94795aSAndroid Build Coastguard Worker
104*9e94795aSAndroid Build Coastguard Workerfunc init() {
105*9e94795aSAndroid Build Coastguard Worker	for _, safePathPrefix := range safePathPrefixes {
106*9e94795aSAndroid Build Coastguard Worker		if strings.HasPrefix(safePathPrefix.prefix, "prebuilts/") {
107*9e94795aSAndroid Build Coastguard Worker			continue
108*9e94795aSAndroid Build Coastguard Worker		}
109*9e94795aSAndroid Build Coastguard Worker		r := regexp.MustCompile("^prebuilts/(?:runtime/mainline/)?" + safePathPrefix.prefix)
110*9e94795aSAndroid Build Coastguard Worker		safePrebuiltPrefixes = append(safePrebuiltPrefixes,
111*9e94795aSAndroid Build Coastguard Worker			safePrebuiltPrefixesType{safePathPrefix, r})
112*9e94795aSAndroid Build Coastguard Worker	}
113*9e94795aSAndroid Build Coastguard Worker}
114*9e94795aSAndroid Build Coastguard Worker
115*9e94795aSAndroid Build Coastguard Worker// LicenseConditionSetFromNames returns a set containing the recognized `names` and
116*9e94795aSAndroid Build Coastguard Worker// silently ignoring or discarding the unrecognized `names`.
117*9e94795aSAndroid Build Coastguard Workerfunc LicenseConditionSetFromNames(names ...string) LicenseConditionSet {
118*9e94795aSAndroid Build Coastguard Worker	cs := NewLicenseConditionSet()
119*9e94795aSAndroid Build Coastguard Worker	for _, name := range names {
120*9e94795aSAndroid Build Coastguard Worker		if lc, ok := RecognizedConditionNames[name]; ok {
121*9e94795aSAndroid Build Coastguard Worker			cs |= LicenseConditionSet(lc)
122*9e94795aSAndroid Build Coastguard Worker		}
123*9e94795aSAndroid Build Coastguard Worker	}
124*9e94795aSAndroid Build Coastguard Worker	return cs
125*9e94795aSAndroid Build Coastguard Worker}
126*9e94795aSAndroid Build Coastguard Worker
127*9e94795aSAndroid Build Coastguard Worker// Resolution happens in three phases:
128*9e94795aSAndroid Build Coastguard Worker//
129*9e94795aSAndroid Build Coastguard Worker// 1. A bottom-up traversal propagates (restricted) license conditions up to
130*9e94795aSAndroid Build Coastguard Worker// targets from dendencies as needed.
131*9e94795aSAndroid Build Coastguard Worker//
132*9e94795aSAndroid Build Coastguard Worker// 2. For each condition of interest, a top-down traversal propagates
133*9e94795aSAndroid Build Coastguard Worker// (restricted) conditions down from targets into linked dependencies.
134*9e94795aSAndroid Build Coastguard Worker//
135*9e94795aSAndroid Build Coastguard Worker// 3. Finally, a walk of the shipped target nodes attaches resolutions to the
136*9e94795aSAndroid Build Coastguard Worker// ancestor nodes from the root down to and including the first non-container.
137*9e94795aSAndroid Build Coastguard Worker//
138*9e94795aSAndroid Build Coastguard Worker// e.g. If a disk image contains a binary bin1 that links a library liba, the
139*9e94795aSAndroid Build Coastguard Worker// notice requirement for liba gets attached to the disk image and to bin1.
140*9e94795aSAndroid Build Coastguard Worker// Because liba doesn't actually get shipped as a separate artifact, but only
141*9e94795aSAndroid Build Coastguard Worker// as bits in bin1, it has no actions 'attached' to it. The actions attached
142*9e94795aSAndroid Build Coastguard Worker// to the image and to bin1 'act on' liba by providing notice.
143*9e94795aSAndroid Build Coastguard Worker//
144*9e94795aSAndroid Build Coastguard Worker// The behavior of the 3 phases gets controlled by the 3 functions below.
145*9e94795aSAndroid Build Coastguard Worker//
146*9e94795aSAndroid Build Coastguard Worker// The first function controls what happens during the bottom-up propagation.
147*9e94795aSAndroid Build Coastguard Worker// Restricted conditions propagate up all non-toolchain dependencies; except,
148*9e94795aSAndroid Build Coastguard Worker// some do not propagate up dynamic links, which may depend on whether the
149*9e94795aSAndroid Build Coastguard Worker// modules are independent.
150*9e94795aSAndroid Build Coastguard Worker//
151*9e94795aSAndroid Build Coastguard Worker// The second function controls what happens during the top-down propagation.
152*9e94795aSAndroid Build Coastguard Worker// Restricted conditions propagate down as above with the added caveat that
153*9e94795aSAndroid Build Coastguard Worker// inherited restricted conditions do not propagate from pure aggregates to
154*9e94795aSAndroid Build Coastguard Worker// their dependencies.
155*9e94795aSAndroid Build Coastguard Worker//
156*9e94795aSAndroid Build Coastguard Worker// The final function controls which conditions apply/get attached to ancestors
157*9e94795aSAndroid Build Coastguard Worker// depending on the types of dependencies involved. All conditions apply across
158*9e94795aSAndroid Build Coastguard Worker// normal derivation dependencies. No conditions apply across toolchain
159*9e94795aSAndroid Build Coastguard Worker// dependencies. Some restricted conditions apply across dynamic link
160*9e94795aSAndroid Build Coastguard Worker// dependencies.
161*9e94795aSAndroid Build Coastguard Worker//
162*9e94795aSAndroid Build Coastguard Worker// Not all restricted licenses are create equal. Some have special rules or
163*9e94795aSAndroid Build Coastguard Worker// exceptions. e.g. LGPL or "with classpath excption".
164*9e94795aSAndroid Build Coastguard Worker
165*9e94795aSAndroid Build Coastguard Worker// depConditionsPropagatingToTarget returns the conditions which propagate up an
166*9e94795aSAndroid Build Coastguard Worker// edge from dependency to target.
167*9e94795aSAndroid Build Coastguard Worker//
168*9e94795aSAndroid Build Coastguard Worker// This function sets the policy for the bottom-up propagation and how conditions
169*9e94795aSAndroid Build Coastguard Worker// flow up the graph from dependencies to targets.
170*9e94795aSAndroid Build Coastguard Worker//
171*9e94795aSAndroid Build Coastguard Worker// If a pure aggregation is built into a derivative work that is not a pure
172*9e94795aSAndroid Build Coastguard Worker// aggregation, per policy it ceases to be a pure aggregation in the context of
173*9e94795aSAndroid Build Coastguard Worker// that derivative work. The `treatAsAggregate` parameter will be false for
174*9e94795aSAndroid Build Coastguard Worker// non-aggregates and for aggregates in non-aggregate contexts.
175*9e94795aSAndroid Build Coastguard Workerfunc depConditionsPropagatingToTarget(lg *LicenseGraph, e *TargetEdge, depConditions LicenseConditionSet, treatAsAggregate bool) LicenseConditionSet {
176*9e94795aSAndroid Build Coastguard Worker	result := LicenseConditionSet(0x0000)
177*9e94795aSAndroid Build Coastguard Worker	if edgeIsDerivation(e) {
178*9e94795aSAndroid Build Coastguard Worker		result |= depConditions & ImpliesRestricted
179*9e94795aSAndroid Build Coastguard Worker		return result
180*9e94795aSAndroid Build Coastguard Worker	}
181*9e94795aSAndroid Build Coastguard Worker	if !edgeIsDynamicLink(e) {
182*9e94795aSAndroid Build Coastguard Worker		return result
183*9e94795aSAndroid Build Coastguard Worker	}
184*9e94795aSAndroid Build Coastguard Worker
185*9e94795aSAndroid Build Coastguard Worker	result |= depConditions & LicenseConditionSet(RestrictedCondition)
186*9e94795aSAndroid Build Coastguard Worker	return result
187*9e94795aSAndroid Build Coastguard Worker}
188*9e94795aSAndroid Build Coastguard Worker
189*9e94795aSAndroid Build Coastguard Worker// targetConditionsPropagatingToDep returns the conditions which propagate down
190*9e94795aSAndroid Build Coastguard Worker// an edge from target to dependency.
191*9e94795aSAndroid Build Coastguard Worker//
192*9e94795aSAndroid Build Coastguard Worker// This function sets the policy for the top-down traversal and how conditions
193*9e94795aSAndroid Build Coastguard Worker// flow down the graph from targets to dependencies.
194*9e94795aSAndroid Build Coastguard Worker//
195*9e94795aSAndroid Build Coastguard Worker// If a pure aggregation is built into a derivative work that is not a pure
196*9e94795aSAndroid Build Coastguard Worker// aggregation, per policy it ceases to be a pure aggregation in the context of
197*9e94795aSAndroid Build Coastguard Worker// that derivative work. The `treatAsAggregate` parameter will be false for
198*9e94795aSAndroid Build Coastguard Worker// non-aggregates and for aggregates in non-aggregate contexts.
199*9e94795aSAndroid Build Coastguard Workerfunc targetConditionsPropagatingToDep(lg *LicenseGraph, e *TargetEdge, targetConditions LicenseConditionSet, treatAsAggregate bool, conditionsFn TraceConditions) LicenseConditionSet {
200*9e94795aSAndroid Build Coastguard Worker	result := targetConditions
201*9e94795aSAndroid Build Coastguard Worker
202*9e94795aSAndroid Build Coastguard Worker	// reverse direction -- none of these apply to things depended-on, only to targets depending-on.
203*9e94795aSAndroid Build Coastguard Worker	result = result.Minus(UnencumberedCondition, PermissiveCondition, NoticeCondition, ReciprocalCondition, ProprietaryCondition, ByExceptionOnlyCondition)
204*9e94795aSAndroid Build Coastguard Worker
205*9e94795aSAndroid Build Coastguard Worker	if !edgeIsDerivation(e) && !edgeIsDynamicLink(e) {
206*9e94795aSAndroid Build Coastguard Worker		// target is not a derivative work of dependency and is not linked to dependency
207*9e94795aSAndroid Build Coastguard Worker		result = result.Difference(ImpliesRestricted)
208*9e94795aSAndroid Build Coastguard Worker		return result
209*9e94795aSAndroid Build Coastguard Worker	}
210*9e94795aSAndroid Build Coastguard Worker	if treatAsAggregate {
211*9e94795aSAndroid Build Coastguard Worker		// If the author of a pure aggregate licenses it restricted, apply restricted to immediate dependencies.
212*9e94795aSAndroid Build Coastguard Worker		// Otherwise, restricted does not propagate back down to dependencies.
213*9e94795aSAndroid Build Coastguard Worker		if !conditionsFn(e.target).MatchesAnySet(ImpliesRestricted) {
214*9e94795aSAndroid Build Coastguard Worker			result = result.Difference(ImpliesRestricted)
215*9e94795aSAndroid Build Coastguard Worker		}
216*9e94795aSAndroid Build Coastguard Worker		return result
217*9e94795aSAndroid Build Coastguard Worker	}
218*9e94795aSAndroid Build Coastguard Worker	if edgeIsDerivation(e) {
219*9e94795aSAndroid Build Coastguard Worker		return result
220*9e94795aSAndroid Build Coastguard Worker	}
221*9e94795aSAndroid Build Coastguard Worker	result = result.Minus(WeaklyRestrictedCondition)
222*9e94795aSAndroid Build Coastguard Worker	return result
223*9e94795aSAndroid Build Coastguard Worker}
224*9e94795aSAndroid Build Coastguard Worker
225*9e94795aSAndroid Build Coastguard Worker// conditionsAttachingAcrossEdge returns the subset of conditions in `universe`
226*9e94795aSAndroid Build Coastguard Worker// that apply across edge `e`.
227*9e94795aSAndroid Build Coastguard Worker//
228*9e94795aSAndroid Build Coastguard Worker// This function sets the policy for attaching actions to ancestor nodes in the
229*9e94795aSAndroid Build Coastguard Worker// final resolution walk.
230*9e94795aSAndroid Build Coastguard Workerfunc conditionsAttachingAcrossEdge(lg *LicenseGraph, e *TargetEdge, universe LicenseConditionSet) LicenseConditionSet {
231*9e94795aSAndroid Build Coastguard Worker	result := universe
232*9e94795aSAndroid Build Coastguard Worker	if edgeIsDerivation(e) {
233*9e94795aSAndroid Build Coastguard Worker		return result
234*9e94795aSAndroid Build Coastguard Worker	}
235*9e94795aSAndroid Build Coastguard Worker	if !edgeIsDynamicLink(e) {
236*9e94795aSAndroid Build Coastguard Worker		return NewLicenseConditionSet()
237*9e94795aSAndroid Build Coastguard Worker	}
238*9e94795aSAndroid Build Coastguard Worker
239*9e94795aSAndroid Build Coastguard Worker	result &= LicenseConditionSet(RestrictedCondition)
240*9e94795aSAndroid Build Coastguard Worker	return result
241*9e94795aSAndroid Build Coastguard Worker}
242*9e94795aSAndroid Build Coastguard Worker
243*9e94795aSAndroid Build Coastguard Worker// edgeIsDynamicLink returns true for edges representing shared libraries
244*9e94795aSAndroid Build Coastguard Worker// linked dynamically at runtime.
245*9e94795aSAndroid Build Coastguard Workerfunc edgeIsDynamicLink(e *TargetEdge) bool {
246*9e94795aSAndroid Build Coastguard Worker	return e.annotations.HasAnnotation("dynamic")
247*9e94795aSAndroid Build Coastguard Worker}
248*9e94795aSAndroid Build Coastguard Worker
249*9e94795aSAndroid Build Coastguard Worker// edgeIsDerivation returns true for edges where the target is a derivative
250*9e94795aSAndroid Build Coastguard Worker// work of dependency.
251*9e94795aSAndroid Build Coastguard Workerfunc edgeIsDerivation(e *TargetEdge) bool {
252*9e94795aSAndroid Build Coastguard Worker	isDynamic := e.annotations.HasAnnotation("dynamic")
253*9e94795aSAndroid Build Coastguard Worker	isToolchain := e.annotations.HasAnnotation("toolchain")
254*9e94795aSAndroid Build Coastguard Worker	return !isDynamic && !isToolchain
255*9e94795aSAndroid Build Coastguard Worker}
256