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 */ verifyRetentionSatisfiedBynull67internal 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 */ verifyDeletionTriggersSatisfiedBynull81internal 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 */ satisfiesnull91internal 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