forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDerivedDataEgressPolicy.swift
More file actions
73 lines (63 loc) · 2.97 KB
/
Copy pathDerivedDataEgressPolicy.swift
File metadata and controls
73 lines (63 loc) · 2.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import Foundation
/// The complete policy for data derived from local context/proactivity state.
///
/// This is deliberately default-deny: a new `DerivedDataClass` has no egress until
/// its declaration is changed here and a named route is registered below. Today the
/// sole exception is minimal meeting identity used by server-side summarization.
enum DerivedDataClass: String, CaseIterable, Sendable {
case meetingIdentity = "meeting_identity"
case contextBucketFacts = "context_bucket_facts"
case contextBucketNarratives = "context_bucket_narratives"
case contextBucketEntries = "context_bucket_entries"
case proactiveNotificationDerivation = "proactive_notification_derivation"
}
enum DerivedDataEgressRoute: String, CaseIterable, Sendable {
case calendarMeetings = "POST /v1/calendar/meetings"
}
struct DerivedDataEgressRequest: Equatable, Sendable {
let dataClass: DerivedDataClass
let route: DerivedDataEgressRoute
let purpose: String
}
enum DerivedDataEgressDecision: Equatable, Sendable {
case allow(purpose: String)
case deny(reason: String)
}
enum DerivedDataEgressPolicyError: Error, Equatable {
case denied(DerivedDataClass)
case undeclaredRoute(DerivedDataClass, DerivedDataEgressRoute)
case purposeMismatch(DerivedDataClass)
}
enum DerivedDataEgressPolicy {
static let meetingIdentityPurpose = "server-side conversation summarization"
/// Human-readable declarations. Missing entries are denied by `decision(for:)`.
static let declarations: [DerivedDataClass: DerivedDataEgressDecision] = [
.meetingIdentity: .allow(purpose: meetingIdentityPurpose),
.contextBucketFacts: .deny(reason: "proactive-notification derivation stays on-device"),
.contextBucketNarratives: .deny(reason: "proactive-notification derivation stays on-device"),
.contextBucketEntries: .deny(reason: "proactive-notification derivation stays on-device"),
.proactiveNotificationDerivation: .deny(reason: "proactive notifications are computed and consumed on-device"),
]
/// Every production transport for derived data must be named here. CI asserts
/// that no registered route belongs to a denied class.
static let declaredRoutes: [DerivedDataEgressRequest] = [
DerivedDataEgressRequest(
dataClass: .meetingIdentity,
route: .calendarMeetings,
purpose: meetingIdentityPurpose)
]
static func decision(for dataClass: DerivedDataClass) -> DerivedDataEgressDecision {
declarations[dataClass] ?? .deny(reason: "no egress declaration")
}
static func authorize(_ request: DerivedDataEgressRequest) throws {
guard case .allow(let declaredPurpose) = decision(for: request.dataClass) else {
throw DerivedDataEgressPolicyError.denied(request.dataClass)
}
guard declaredRoutes.contains(request) else {
throw DerivedDataEgressPolicyError.undeclaredRoute(request.dataClass, request.route)
}
guard request.purpose == declaredPurpose else {
throw DerivedDataEgressPolicyError.purposeMismatch(request.dataClass)
}
}
}