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.api.policy
18
19 import com.android.libraries.pcc.chronicle.api.policy.annotation.Annotation
20 import com.android.libraries.pcc.chronicle.api.policy.capabilities.Capabilities
21 import com.android.libraries.pcc.chronicle.api.policy.capabilities.Capability
22 import com.android.libraries.pcc.chronicle.api.policy.contextrules.All
23 import com.android.libraries.pcc.chronicle.api.policy.contextrules.PolicyContextRule
24
25 /** The name of a field within an entity. */
26 typealias FieldName = String
27
28 /** Defines a data usage policy. See [PolicyProto] for the canonical definition of a policy. */
29 data class Policy(
30 val name: String,
31 val egressType: String,
32 val description: String = "",
33 val targets: List<PolicyTarget> = emptyList(),
34 val configs: Map<String, PolicyConfig> = emptyMap(),
35 val annotations: List<Annotation> = emptyList(),
36 val allowedContext: PolicyContextRule = All
37 ) {
38 /** All fields mentioned the policy (includes nested fields). */
39 val allFields: List<PolicyField> = collectAllFields()
40
41 /** The set of all redaction labels mentioned in the policy. */
42 val allRedactionLabels: Set<String> = allFields.flatMap { it.redactedUsages.keys }.toSet()
43
44 private fun collectAllFields(): List<PolicyField> {
45 fun getAllFields(field: PolicyField): List<PolicyField> {
46 return listOf(field) + field.subfields.flatMap { getAllFields(it) }
47 }
48 return targets.flatMap { target -> target.fields.flatMap { getAllFields(it) } }
49 }
50 }
51
52 /** Target schema governed by a policy, see [PolicyTargetProto]. */
53 data class PolicyTarget(
54 val schemaName: String,
55 val maxAgeMs: Long = 0,
56 val retentions: List<PolicyRetention> = emptyList(),
57 val fields: List<PolicyField> = emptyList(),
58 val annotations: List<Annotation> = emptyList()
59 ) {
60
toCapabilitiesnull61 fun toCapabilities(): List<Capabilities> {
62 return retentions.map {
63 val ranges = mutableListOf<Capability>()
64 ranges.add(
65 when (it.medium) {
66 StorageMedium.DISK -> Capability.Persistence.ON_DISK
67 StorageMedium.RAM -> Capability.Persistence.IN_MEMORY
68 }
69 )
70 if (it.encryptionRequired) {
71 ranges.add(Capability.Encryption(true))
72 }
73 ranges.add(Capability.Ttl.Minutes((maxAgeMs / Capability.Ttl.MILLIS_IN_MIN).toInt()))
74 Capabilities(ranges)
75 }
76 }
77 }
78
79 /** Allowed usages for fields in a schema, see [PolicyFieldProto]. */
80 data class PolicyField(
81 /** List of field names leading from the [PolicyTarget] to this nested field. */
82 val fieldPath: List<FieldName>,
83 /** Valid usages of this field without redaction. */
84 val rawUsages: Set<UsageType> = emptySet(),
85 /** Valid usages of this field with redaction first. Maps from redaction label to usages. */
86 val redactedUsages: Map<String, Set<UsageType>> = emptyMap(),
87 val subfields: List<PolicyField> = emptyList(),
88 val annotations: List<Annotation> = emptyList()
89 ) {
90 init {
subfieldnull91 subfields.forEach { subfield ->
92 require(
93 fieldPath.size < subfield.fieldPath.size &&
94 subfield.fieldPath.subList(0, fieldPath.size) == fieldPath
95 ) {
96 "Subfield's field path must be nested inside parent's field path, " +
97 "but got parent: '$fieldPath', child: '${subfield.fieldPath}'."
98 }
99 }
100 }
101 }
102
103 /** Retention options for storing data, see [PolicyRetentionProto]. */
104 data class PolicyRetention(val medium: StorageMedium, val encryptionRequired: Boolean = false)
105
106 /**
107 * Config options specified by a policy, see [PolicyConfigProto]. These are arbitrary string
108 * key-value pairs set by the policy author. They have no direct affect on the policy itself.
109 */
110 typealias PolicyConfig = Map<String, String>
111
112 /** Type of usage permitted of a field, see [PolicyFieldProto.UsageType]. */
113 enum class UsageType {
114 ANY,
115 EGRESS,
116 JOIN,
117 SANDBOX;
118
119 val canEgress
120 get() = this == ANY || this == EGRESS
121 }
122
123 /** Convenience method for checking if any usage in a set allows egress. */
canEgressnull124 fun Set<UsageType>.canEgress(): Boolean = any { it.canEgress }
125
126 /** Target schema governed by a policy, see [PolicyRetentionProto.Medium]. */
127 enum class StorageMedium {
128 RAM,
129 DISK,
130 }
131