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