• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.libraries.pcc.chronicle.analysis.impl
18 
19 import com.android.libraries.pcc.chronicle.analysis.ManagementStrategyComparator.compare
20 import com.android.libraries.pcc.chronicle.analysis.retentionsAsManagementStrategies
21 import com.android.libraries.pcc.chronicle.api.ConnectionProvider
22 import com.android.libraries.pcc.chronicle.api.DataType
23 import com.android.libraries.pcc.chronicle.api.DeletionTrigger
24 import com.android.libraries.pcc.chronicle.api.ManagementStrategy
25 import com.android.libraries.pcc.chronicle.api.policy.Policy
26 import com.android.libraries.pcc.chronicle.api.policy.PolicyRetention
27 import com.android.libraries.pcc.chronicle.api.policy.PolicyTarget
28 import com.android.libraries.pcc.chronicle.api.policy.builder.PolicyCheck
29 import com.android.libraries.pcc.chronicle.api.policy.builder.deletionTriggers
30 
31 /**
32  * Verifies that [ManagementStrategy] values declared by the [ConnectionProviders]
33  * [ConnectionProvider] are valid given policy-requirements for the receiving [Policy] object.
34  *
35  * @return a list of [Checks][PolicyCheck]. If empty, the implication is that policy adherence is
36  * satisfied. If non-empty, the values will describe how policy is not being met.
37  */
38 internal fun Policy.verifyManagementStrategies(
39   connectionProviders: Collection<ConnectionProvider>
40 ): List<PolicyCheck> {
41   val targetsBySchemaName = targets.map(PolicyTarget::schemaName).toSet()
42   val managedDataTypesBySchemaName =
43     connectionProviders
44       .asSequence()
45       .map { it.dataType }
46       // Ensure that this managed data type is mentioned by the policy.
47       .filter { it.descriptor.name in targetsBySchemaName }
48       .associateBy { it.descriptor.name }
49 
50   return targets.flatMap { target ->
51     // If there is no managed data type for the target, it means that the policy contains an extra
52     // target, which is no problem - skip it.
53     val dataType = managedDataTypesBySchemaName[target.schemaName] ?: return@flatMap emptyList()
54 
55     val retentionViolations = target.verifyRetentionSatisfiedBy(dataType)
56     val deletionViolations = target.verifyDeletionTriggersSatisfiedBy(dataType)
57 
58     retentionViolations + deletionViolations
59   }
60 }
61 
62 /**
63  * Verifies that one of the receiving [PolicyTarget]'s [PolicyRetentions][PolicyRetention] and the
64  * max age are satisfied by the given [strategy]. Returns a list of any failing [Checks]
65  * [PolicyCheck] (one per unsatisfied [PolicyRetention]) if-and-only-if all retentions fail.
66  */
verifyRetentionSatisfiedBynull67 internal fun PolicyTarget.verifyRetentionSatisfiedBy(dataType: DataType): List<PolicyCheck> {
68   val strategy = dataType.managementStrategy
69   val failedRetentions = retentionsAsManagementStrategies().filter { compare(strategy, it) > 0 }
70   if (failedRetentions.size < retentions.size) return emptyList()
71 
72   return retentions.map {
73     PolicyCheck("h:${dataType.descriptor.name} is $it with maxAgeMs = $maxAgeMs")
74   }
75 }
76 
77 /**
78  * Verifies that any deletion triggers required by the receiving [PolicyTarget] are satisfied by the
79  * given [ManagementStrategy]. Returns any violations as [Checks][PolicyCheck].
80  */
verifyDeletionTriggersSatisfiedBynull81 internal fun PolicyTarget.verifyDeletionTriggersSatisfiedBy(dataType: DataType): List<PolicyCheck> {
82   val strategy = dataType.managementStrategy
83   val missingDeletionTriggers = this.deletionTriggers().filter { !strategy.satisfies(it) }
84 
85   return missingDeletionTriggers.map { PolicyCheck("h:${dataType.descriptor.name} is $it") }
86 }
87 
88 /**
89  * Returns whether or not the receiving [ManagementStrategy] satisfies the given [DeletionTrigger].
90  */
satisfiesnull91 internal fun ManagementStrategy.satisfies(policyDeletionTrigger: DeletionTrigger): Boolean {
92   return when (this) {
93     ManagementStrategy.PassThru -> true
94     is ManagementStrategy.Stored -> this.deletionTriggers.contains(policyDeletionTrigger)
95   }
96 }
97