@amityco/social-plus-vise 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,66 @@
1
+ {
2
+ "domain": "live-data",
3
+ "schema_version": 1,
4
+ "rules": [
5
+ {
6
+ "id": "android.live.cleanup",
7
+ "version": 1,
8
+ "title": "Android live data observers must be cleaned up",
9
+ "severity": "warning",
10
+ "rationale": "Live Object and Live Collection observers should be disposed when their lifecycle owner ends.",
11
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-live-data", "add-feed", "validate-setup"] },
12
+ "enforcement": {
13
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.live.cleanup" }],
14
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "lifecycle_owner", "description": "Lifecycle owner and cleanup location.", "upload_policy": "upload-with-consent" }] }
15
+ }
16
+ },
17
+ {
18
+ "id": "flutter.live.cleanup",
19
+ "version": 1,
20
+ "title": "Flutter live data subscriptions must be cleaned up",
21
+ "severity": "warning",
22
+ "rationale": "Live Object and Live Collection subscriptions should be cancelled from dispose or equivalent cleanup.",
23
+ "applies_when": { "platforms": ["flutter"], "outcomes": ["setup-live-data", "add-feed", "validate-setup"] },
24
+ "enforcement": {
25
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "flutter.live.cleanup" }],
26
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "lifecycle_owner", "description": "Lifecycle owner and cleanup location.", "upload_policy": "upload-with-consent" }] }
27
+ }
28
+ },
29
+ {
30
+ "id": "typescript.live.cleanup",
31
+ "version": 1,
32
+ "title": "TypeScript live data subscriptions must be cleaned up",
33
+ "severity": "warning",
34
+ "rationale": "Live Object and Live Collection subscriptions should be unsubscribed from the owning component, route, or store lifecycle.",
35
+ "applies_when": { "platforms": ["typescript"], "outcomes": ["setup-live-data", "add-feed", "validate-setup"] },
36
+ "enforcement": {
37
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "typescript.live.cleanup" }],
38
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "lifecycle_owner", "description": "Lifecycle owner and cleanup location.", "upload_policy": "upload-with-consent" }] }
39
+ }
40
+ },
41
+ {
42
+ "id": "react-native.live.cleanup",
43
+ "version": 1,
44
+ "title": "React Native live data subscriptions must be cleaned up",
45
+ "severity": "warning",
46
+ "rationale": "Live Object and Live Collection subscriptions should be unsubscribed from the owning component, route, or store lifecycle.",
47
+ "applies_when": { "platforms": ["react-native"], "outcomes": ["setup-live-data", "add-feed", "validate-setup"] },
48
+ "enforcement": {
49
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "react-native.live.cleanup" }],
50
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "lifecycle_owner", "description": "Lifecycle owner and cleanup location.", "upload_policy": "upload-with-consent" }] }
51
+ }
52
+ },
53
+ {
54
+ "id": "ios.live.cleanup",
55
+ "version": 1,
56
+ "title": "iOS live data observers must be cleaned up",
57
+ "severity": "warning",
58
+ "rationale": "Live Object and Live Collection notification tokens should be invalidated when the view, controller, or owning object's lifecycle ends.",
59
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-live-data", "add-feed", "validate-setup"] },
60
+ "enforcement": {
61
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.live.cleanup" }],
62
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "lifecycle_owner", "description": "Lifecycle owner and cleanup location (deinit, viewWillDisappear, etc.).", "upload_policy": "upload-with-consent" }] }
63
+ }
64
+ }
65
+ ]
66
+ }
@@ -0,0 +1,95 @@
1
+ {
2
+ "domain": "push",
3
+ "schema_version": 1,
4
+ "rules": [
5
+ {
6
+ "id": "android.push.unregister.present",
7
+ "version": 1,
8
+ "title": "Android push unregister must exist on logout or user switch",
9
+ "severity": "warning",
10
+ "rationale": "Registered device tokens are associated with a user. Missing unregister can deliver notifications to the wrong user.",
11
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-push", "validate-setup"] },
12
+ "enforcement": {
13
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.push.unregister.present" }],
14
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "trigger", "description": "Logout or user-switch flow that unregisters the device token.", "upload_policy": "upload-with-consent" }] }
15
+ }
16
+ },
17
+ {
18
+ "id": "flutter.push.unregister.present",
19
+ "version": 1,
20
+ "title": "Flutter push unregister must exist on logout or user switch",
21
+ "severity": "warning",
22
+ "rationale": "Registered device tokens are associated with a user. Missing unregister can deliver notifications to the wrong user.",
23
+ "applies_when": { "platforms": ["flutter"], "outcomes": ["setup-push", "validate-setup"] },
24
+ "enforcement": {
25
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "flutter.push.unregister.present" }],
26
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "trigger", "description": "Logout or user-switch flow that unregisters the device token.", "upload_policy": "upload-with-consent" }] }
27
+ }
28
+ },
29
+ {
30
+ "id": "typescript.push.unregister.present",
31
+ "version": 1,
32
+ "title": "TypeScript push unregister must exist on logout or user switch",
33
+ "severity": "warning",
34
+ "rationale": "Registered device tokens are associated with a user. Missing unregister can deliver notifications to the wrong user.",
35
+ "applies_when": { "platforms": ["typescript"], "outcomes": ["setup-push", "validate-setup"] },
36
+ "enforcement": {
37
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "typescript.push.unregister.present" }],
38
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "trigger", "description": "Logout or user-switch flow that unregisters the device token.", "upload_policy": "upload-with-consent" }] }
39
+ }
40
+ },
41
+ {
42
+ "id": "react-native.push.unregister.present",
43
+ "version": 1,
44
+ "title": "React Native push unregister must exist on logout or user switch",
45
+ "severity": "warning",
46
+ "rationale": "Registered device tokens are associated with a user. Missing unregister can deliver notifications to the wrong user.",
47
+ "applies_when": { "platforms": ["react-native"], "outcomes": ["setup-push", "validate-setup"] },
48
+ "enforcement": {
49
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "react-native.push.unregister.present" }],
50
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "trigger", "description": "Logout or user-switch flow that unregisters the device token.", "upload_policy": "upload-with-consent" }] }
51
+ }
52
+ },
53
+ {
54
+ "id": "ios.push.unregister.present",
55
+ "version": 1,
56
+ "title": "iOS push unregister must exist on logout or user switch",
57
+ "severity": "warning",
58
+ "rationale": "Registered device tokens are associated with a user. Missing unregister can deliver notifications to the wrong user.",
59
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-push", "validate-setup"] },
60
+ "enforcement": {
61
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.push.unregister.present" }],
62
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "trigger", "description": "Logout or user-switch flow that unregisters the device token.", "upload_policy": "upload-with-consent" }] }
63
+ }
64
+ },
65
+ {
66
+ "id": "android.push.firebase-config",
67
+ "version": 1,
68
+ "title": "Firebase configuration file must be present for Android push setup",
69
+ "severity": "warning",
70
+ "rationale": "Firebase Cloud Messaging requires google-services.json in the Android app module to obtain device tokens. Without it, the SDK cannot register for push notifications.",
71
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-push"] },
72
+ "enforcement": {
73
+ "blockers": [
74
+ {
75
+ "check": "file-absent",
76
+ "path": "app/google-services.json",
77
+ "reason": "google-services.json is missing from the app module. Download it from your Firebase project console (Project settings → Your apps → Android app → google-services.json) and place it at app/google-services.json before push registration can work."
78
+ }
79
+ ],
80
+ "attestation": {
81
+ "allowed": true,
82
+ "host_agent_min_confidence": "high",
83
+ "human_allowed": true,
84
+ "evidence_required": [
85
+ {
86
+ "field": "config_location",
87
+ "description": "Where the Firebase configuration is loaded from if not the default app/google-services.json path.",
88
+ "upload_policy": "upload-with-consent"
89
+ }
90
+ ]
91
+ }
92
+ }
93
+ }
94
+ ]
95
+ }
@@ -0,0 +1,422 @@
1
+ {
2
+ "domain": "sdk-lifecycle",
3
+ "schema_version": 1,
4
+ "rules": [
5
+ {
6
+ "id": "android.permission.internet",
7
+ "version": 1,
8
+ "title": "Android INTERNET permission must be declared",
9
+ "severity": "error",
10
+ "rationale": "The SDK needs network access. Missing INTERNET permission blocks social.plus API calls on Android.",
11
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
12
+ "enforcement": {
13
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.permission.internet" }],
14
+ "attestation": { "allowed": false, "host_agent_min_confidence": "high", "human_allowed": false, "evidence_required": [] }
15
+ }
16
+ },
17
+ {
18
+ "id": "android.application.class",
19
+ "version": 1,
20
+ "title": "Android SDK setup should use an Application class",
21
+ "severity": "warning",
22
+ "rationale": "Application startup avoids repeated SDK setup from Activity, Fragment, or UI lifecycle recreation.",
23
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
24
+ "enforcement": {
25
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.application.class" }],
26
+ "attestation": {
27
+ "allowed": true,
28
+ "host_agent_min_confidence": "high",
29
+ "human_allowed": true,
30
+ "evidence_required": [
31
+ { "field": "file_path", "description": "Application or startup file containing SDK setup.", "upload_policy": "redact-paths-under: [\"src/secrets/\", \"config/credentials/\"]" },
32
+ { "field": "entrypoint_chain", "description": "Call chain from app startup to SDK setup.", "upload_policy": "upload-with-consent" }
33
+ ]
34
+ }
35
+ }
36
+ },
37
+ {
38
+ "id": "android.setup.present",
39
+ "version": 1,
40
+ "title": "Android SDK setup must be present",
41
+ "severity": "warning",
42
+ "rationale": "The SDK must be initialized before login or social.plus API usage.",
43
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
44
+ "enforcement": {
45
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.setup.present" }],
46
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "file_path", "description": "Source file containing SDK setup.", "upload_policy": "upload-with-consent" }] }
47
+ }
48
+ },
49
+ {
50
+ "id": "android.setup.lifecycle",
51
+ "version": 1,
52
+ "title": "Android SDK setup should not run in screen lifecycle",
53
+ "severity": "warning",
54
+ "rationale": "Screen lifecycle setup can reinitialize the SDK and create race conditions.",
55
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
56
+ "enforcement": {
57
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.setup.lifecycle" }],
58
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "entrypoint_chain", "description": "Call chain proving setup runs once at app startup.", "upload_policy": "upload-with-consent" }] }
59
+ }
60
+ },
61
+ {
62
+ "id": "android.setup.region",
63
+ "version": 1,
64
+ "title": "Android setup must specify region or endpoint",
65
+ "severity": "warning",
66
+ "rationale": "The SDK region must match the customer's social.plus console project.",
67
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
68
+ "enforcement": {
69
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.setup.region" }],
70
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "region_source", "description": "Where region or endpoint is configured.", "upload_policy": "upload-with-consent" }] }
71
+ }
72
+ },
73
+ {
74
+ "id": "android.login.present",
75
+ "version": 1,
76
+ "title": "Android login must be present",
77
+ "severity": "warning",
78
+ "rationale": "Login must happen after user identity is known and before subscriptions or API calls.",
79
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
80
+ "enforcement": {
81
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.login.present" }],
82
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "login_flow", "description": "Where login is called after user identity is known.", "upload_policy": "upload-with-consent" }] }
83
+ }
84
+ },
85
+ {
86
+ "id": "android.sdk.version.pinned",
87
+ "version": 1,
88
+ "title": "Android SDK dependency should not use a floating version",
89
+ "severity": "warning",
90
+ "rationale": "Floating SDK versions can change APIs or behavior between CI runs without an explicit customer review.",
91
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
92
+ "enforcement": {
93
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.sdk.version.pinned" }],
94
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "version_source", "description": "Dependency file or version catalog proving the SDK version is controlled.", "upload_policy": "upload-with-consent" }] }
95
+ }
96
+ },
97
+ {
98
+ "id": "flutter.binding.initialized",
99
+ "version": 1,
100
+ "title": "Flutter binding must be initialized before async SDK setup",
101
+ "severity": "warning",
102
+ "rationale": "Flutter async setup should call WidgetsFlutterBinding.ensureInitialized before runApp.",
103
+ "applies_when": { "platforms": ["flutter"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
104
+ "enforcement": {
105
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "flutter.binding.initialized" }],
106
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "file_path", "description": "Flutter entrypoint file.", "upload_policy": "upload-with-consent" }] }
107
+ }
108
+ },
109
+ {
110
+ "id": "flutter.setup.present",
111
+ "version": 1,
112
+ "title": "Flutter SDK setup must be present",
113
+ "severity": "warning",
114
+ "rationale": "The SDK must be initialized before login or social.plus API usage.",
115
+ "applies_when": { "platforms": ["flutter"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
116
+ "enforcement": {
117
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "flutter.setup.present" }],
118
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "file_path", "description": "Source file containing SDK setup.", "upload_policy": "upload-with-consent" }] }
119
+ }
120
+ },
121
+ {
122
+ "id": "flutter.setup.region",
123
+ "version": 1,
124
+ "title": "Flutter setup must specify region or endpoint",
125
+ "severity": "warning",
126
+ "rationale": "The SDK region must match the customer's social.plus console project.",
127
+ "applies_when": { "platforms": ["flutter"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
128
+ "enforcement": {
129
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "flutter.setup.region" }],
130
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "region_source", "description": "Where region or endpoint is configured.", "upload_policy": "upload-with-consent" }] }
131
+ }
132
+ },
133
+ {
134
+ "id": "flutter.login.present",
135
+ "version": 1,
136
+ "title": "Flutter login must be present",
137
+ "severity": "warning",
138
+ "rationale": "Login must happen after user identity is known and before subscriptions or API calls.",
139
+ "applies_when": { "platforms": ["flutter"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
140
+ "enforcement": {
141
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "flutter.login.present" }],
142
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "login_flow", "description": "Where login is called after user identity is known.", "upload_policy": "upload-with-consent" }] }
143
+ }
144
+ },
145
+ {
146
+ "id": "flutter.sdk.version.pinned",
147
+ "version": 1,
148
+ "title": "Flutter SDK dependency should not use a floating version",
149
+ "severity": "warning",
150
+ "rationale": "Floating SDK versions can change APIs or behavior between CI runs without an explicit customer review.",
151
+ "applies_when": { "platforms": ["flutter"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
152
+ "enforcement": {
153
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "flutter.sdk.version.pinned" }],
154
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "version_source", "description": "pubspec.yaml or dependency override proving the SDK version is controlled.", "upload_policy": "upload-with-consent" }] }
155
+ }
156
+ },
157
+ {
158
+ "id": "typescript.sdk.version.pinned",
159
+ "version": 1,
160
+ "title": "TypeScript SDK dependency should not use a floating version",
161
+ "severity": "warning",
162
+ "rationale": "Floating SDK versions can change APIs or behavior between CI runs without an explicit customer review.",
163
+ "applies_when": { "platforms": ["typescript"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
164
+ "enforcement": {
165
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "typescript.sdk.version.pinned" }],
166
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "version_source", "description": "package.json, lockfile, or package manager catalog proving the SDK version is controlled.", "upload_policy": "upload-with-consent" }] }
167
+ }
168
+ },
169
+ {
170
+ "id": "react-native.sdk.version.pinned",
171
+ "version": 1,
172
+ "title": "React Native SDK dependency should not use a floating version",
173
+ "severity": "warning",
174
+ "rationale": "Floating SDK versions can change APIs or behavior between CI runs without an explicit customer review.",
175
+ "applies_when": { "platforms": ["react-native"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
176
+ "enforcement": {
177
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "react-native.sdk.version.pinned" }],
178
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "version_source", "description": "package.json, lockfile, or package manager catalog proving the SDK version is controlled.", "upload_policy": "upload-with-consent" }] }
179
+ }
180
+ },
181
+ {
182
+ "id": "typescript.client.create",
183
+ "version": 1,
184
+ "title": "TypeScript client initialization must be present",
185
+ "severity": "warning",
186
+ "rationale": "The client must be created before login or social.plus API usage.",
187
+ "applies_when": { "platforms": ["typescript", "react-native"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
188
+ "enforcement": {
189
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "typescript.client.create" }],
190
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "file_path", "description": "Source file containing client initialization.", "upload_policy": "upload-with-consent" }] }
191
+ }
192
+ },
193
+ {
194
+ "id": "typescript.client.region",
195
+ "version": 1,
196
+ "title": "TypeScript client must specify region or endpoint",
197
+ "severity": "warning",
198
+ "rationale": "The SDK region must match the customer's social.plus console project.",
199
+ "applies_when": { "platforms": ["typescript", "react-native"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
200
+ "enforcement": {
201
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "typescript.client.region" }],
202
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "region_source", "description": "Where region or endpoint is configured.", "upload_policy": "upload-with-consent" }] }
203
+ }
204
+ },
205
+ {
206
+ "id": "typescript.login.present",
207
+ "version": 1,
208
+ "title": "TypeScript login must be present",
209
+ "severity": "warning",
210
+ "rationale": "Login must happen after user identity is known and before subscriptions or API calls.",
211
+ "applies_when": { "platforms": ["typescript", "react-native"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
212
+ "enforcement": {
213
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "typescript.login.present" }],
214
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "login_flow", "description": "Where login is called after user identity is known.", "upload_policy": "upload-with-consent" }] }
215
+ }
216
+ },
217
+ {
218
+ "id": "ios.dependency.manifest",
219
+ "version": 1,
220
+ "title": "iOS project must have a dependency manifest",
221
+ "severity": "warning",
222
+ "rationale": "Foundry needs Podfile or Package.swift to verify the SDK dependency is present.",
223
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
224
+ "enforcement": {
225
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.dependency.manifest" }],
226
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "manifest_path", "description": "Path to the Podfile, Package.swift, or other iOS dependency manifest.", "upload_policy": "upload-with-consent" }] }
227
+ }
228
+ },
229
+ {
230
+ "id": "ios.dependency.sdk",
231
+ "version": 1,
232
+ "title": "iOS dependency manifest must include the social.plus SDK",
233
+ "severity": "warning",
234
+ "rationale": "The Amity iOS SDK dependency must be declared in the project's dependency manifest.",
235
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
236
+ "enforcement": {
237
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.dependency.sdk" }],
238
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "manifest_path", "description": "Manifest declaring the social.plus SDK dependency.", "upload_policy": "upload-with-consent" }] }
239
+ }
240
+ },
241
+ {
242
+ "id": "ios.sdk.version.pinned",
243
+ "version": 1,
244
+ "title": "iOS SDK dependency should not use a floating version",
245
+ "severity": "warning",
246
+ "rationale": "Floating SDK versions can change APIs or behavior between CI runs without an explicit customer review.",
247
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
248
+ "enforcement": {
249
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.sdk.version.pinned" }],
250
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "version_source", "description": "Package.swift, Podfile, or lockfile proving the SDK version is controlled.", "upload_policy": "upload-with-consent" }] }
251
+ }
252
+ },
253
+ {
254
+ "id": "ios.setup.present",
255
+ "version": 1,
256
+ "title": "iOS AmityClient must be initialized",
257
+ "severity": "warning",
258
+ "rationale": "The SDK must be initialized before login or social.plus API usage.",
259
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
260
+ "enforcement": {
261
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.setup.present" }],
262
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "file_path", "description": "Swift file containing AmityClient initialization.", "upload_policy": "upload-with-consent" }] }
263
+ }
264
+ },
265
+ {
266
+ "id": "ios.setup.region",
267
+ "version": 1,
268
+ "title": "iOS AmityClient initialization must specify region",
269
+ "severity": "warning",
270
+ "rationale": "The SDK region must match the customer's social.plus console project.",
271
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
272
+ "enforcement": {
273
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.setup.region" }],
274
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "region_source", "description": "Where region is configured (for example AmityRegion.EU).", "upload_policy": "upload-with-consent" }] }
275
+ }
276
+ },
277
+ {
278
+ "id": "ios.login.present",
279
+ "version": 1,
280
+ "title": "iOS login must be present",
281
+ "severity": "warning",
282
+ "rationale": "Login must happen after user identity is known and before subscriptions or API calls.",
283
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
284
+ "enforcement": {
285
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.login.present" }],
286
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "login_flow", "description": "Where login is called after user identity is known.", "upload_policy": "upload-with-consent" }] }
287
+ }
288
+ },
289
+ {
290
+ "id": "ios.setup.lifecycle",
291
+ "version": 1,
292
+ "title": "iOS SDK setup must not run inside a view or scene lifecycle",
293
+ "severity": "warning",
294
+ "rationale": "Initializing AmityClient inside viewDidLoad / viewWillAppear / scene(_:willConnectTo) re-runs setup as the user navigates between screens. Setup belongs in app process startup (AppDelegate.application(_:didFinishLaunchingWithOptions:) or @main App.init).",
295
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
296
+ "enforcement": {
297
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.setup.lifecycle" }],
298
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "entrypoint_chain", "description": "Call chain from app startup to AmityClient setup.", "upload_policy": "upload-with-consent" }] }
299
+ }
300
+ },
301
+ {
302
+ "id": "android.session.renewal",
303
+ "version": 1,
304
+ "title": "Android login must pass an AmitySessionHandler that renews tokens",
305
+ "severity": "warning",
306
+ "rationale": "Access tokens expire in production. Without a session handler that calls renewal.renew() in sessionWillRenewAccessToken, the SDK cannot refresh sessions and customers see silent auth failures.",
307
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
308
+ "enforcement": {
309
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.session.renewal" }],
310
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "session_handler", "description": "Where AmitySessionHandler.sessionWillRenewAccessToken implementation lives.", "upload_policy": "upload-with-consent" }] }
311
+ }
312
+ },
313
+ {
314
+ "id": "flutter.session.renewal",
315
+ "version": 1,
316
+ "title": "Flutter login must pass an AmitySessionHandler that renews tokens",
317
+ "severity": "warning",
318
+ "rationale": "Access tokens expire in production. Without a session handler that calls renewal.renew() in sessionWillRenewAccessToken, the SDK cannot refresh sessions and customers see silent auth failures.",
319
+ "applies_when": { "platforms": ["flutter"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
320
+ "enforcement": {
321
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "flutter.session.renewal" }],
322
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "session_handler", "description": "Where the Dart session handler implementation lives.", "upload_policy": "upload-with-consent" }] }
323
+ }
324
+ },
325
+ {
326
+ "id": "ios.session.renewal",
327
+ "version": 1,
328
+ "title": "iOS login must pass an AmitySessionHandler that renews tokens",
329
+ "severity": "warning",
330
+ "rationale": "Access tokens expire in production. Without an AmitySessionHandler that calls renewal.renew() in sessionWillRenewAccessToken, the iOS SDK cannot refresh sessions and customers see silent auth failures.",
331
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
332
+ "enforcement": {
333
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.session.renewal" }],
334
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "session_handler", "description": "Where AmitySessionHandler.sessionWillRenewAccessToken implementation lives.", "upload_policy": "upload-with-consent" }] }
335
+ }
336
+ },
337
+ {
338
+ "id": "typescript.session.renewal",
339
+ "version": 1,
340
+ "title": "TypeScript client login must pass a session handler that renews tokens",
341
+ "severity": "warning",
342
+ "rationale": "Access tokens expire in production. Without a sessionHandler / sessionWillRenewAccessToken calling renewal.renew(), the SDK cannot refresh sessions and customers see silent auth failures.",
343
+ "applies_when": { "platforms": ["typescript"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
344
+ "enforcement": {
345
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "typescript.session.renewal" }],
346
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "session_handler", "description": "Where the TypeScript session handler that renews tokens lives.", "upload_policy": "upload-with-consent" }] }
347
+ }
348
+ },
349
+ {
350
+ "id": "react-native.session.renewal",
351
+ "version": 1,
352
+ "title": "React Native client login must pass a session handler that renews tokens",
353
+ "severity": "warning",
354
+ "rationale": "Access tokens expire in production. Without a sessionHandler / sessionWillRenewAccessToken calling renewal.renew(), the SDK cannot refresh sessions and customers see silent auth failures.",
355
+ "applies_when": { "platforms": ["react-native"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
356
+ "enforcement": {
357
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "react-native.session.renewal" }],
358
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "session_handler", "description": "Where the React Native session handler that renews tokens lives.", "upload_policy": "upload-with-consent" }] }
359
+ }
360
+ },
361
+ {
362
+ "id": "android.auth.no-literal-user-id",
363
+ "version": 1,
364
+ "title": "Android login must not pass a hardcoded user identity",
365
+ "severity": "warning",
366
+ "rationale": "userId comes from the host app's auth state (session, account manager, identity provider). A literal userId in source ships a single-user demo to production.",
367
+ "applies_when": { "platforms": ["android"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
368
+ "enforcement": {
369
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "android.auth.no-literal-user-id" }],
370
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "identity_source", "description": "Where the runtime userId comes from (DI scope, route param, account manager, etc.).", "upload_policy": "upload-with-consent" }] }
371
+ }
372
+ },
373
+ {
374
+ "id": "flutter.auth.no-literal-user-id",
375
+ "version": 1,
376
+ "title": "Flutter login must not pass a hardcoded user identity",
377
+ "severity": "warning",
378
+ "rationale": "userId comes from the host app's auth state. A literal userId in source ships a single-user demo to production.",
379
+ "applies_when": { "platforms": ["flutter"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
380
+ "enforcement": {
381
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "flutter.auth.no-literal-user-id" }],
382
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "identity_source", "description": "Where the runtime userId comes from (provider, riverpod, bloc, etc.).", "upload_policy": "upload-with-consent" }] }
383
+ }
384
+ },
385
+ {
386
+ "id": "ios.auth.no-literal-user-id",
387
+ "version": 1,
388
+ "title": "iOS login must not pass a hardcoded user identity",
389
+ "severity": "warning",
390
+ "rationale": "userId comes from the host app's auth state (KeychainStore, identity provider, account manager). A literal userId in source ships a single-user demo to production.",
391
+ "applies_when": { "platforms": ["ios"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
392
+ "enforcement": {
393
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "ios.auth.no-literal-user-id" }],
394
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "identity_source", "description": "Where the runtime userId comes from (Keychain, account service, dependency injection, etc.).", "upload_policy": "upload-with-consent" }] }
395
+ }
396
+ },
397
+ {
398
+ "id": "typescript.auth.no-literal-user-id",
399
+ "version": 1,
400
+ "title": "TypeScript login must not pass a hardcoded user identity",
401
+ "severity": "warning",
402
+ "rationale": "userId comes from the host app's auth state (auth context, route loader, session). A literal userId in source ships a single-user demo to production.",
403
+ "applies_when": { "platforms": ["typescript"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
404
+ "enforcement": {
405
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "typescript.auth.no-literal-user-id" }],
406
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "identity_source", "description": "Where the runtime userId comes from (auth context, session cookie, route loader, etc.).", "upload_policy": "upload-with-consent" }] }
407
+ }
408
+ },
409
+ {
410
+ "id": "react-native.auth.no-literal-user-id",
411
+ "version": 1,
412
+ "title": "React Native login must not pass a hardcoded user identity",
413
+ "severity": "warning",
414
+ "rationale": "userId comes from the host app's auth state. A literal userId in source ships a single-user demo to production.",
415
+ "applies_when": { "platforms": ["react-native"], "outcomes": ["setup-sdk", "setup-push", "setup-live-data", "add-feed", "validate-setup"] },
416
+ "enforcement": {
417
+ "deterministic": [{ "check": "validator-finding-absent", "finding_rule_id": "react-native.auth.no-literal-user-id" }],
418
+ "attestation": { "allowed": true, "host_agent_min_confidence": "high", "human_allowed": true, "evidence_required": [{ "field": "identity_source", "description": "Where the runtime userId comes from (auth context, secure storage, etc.).", "upload_policy": "upload-with-consent" }] }
419
+ }
420
+ }
421
+ ]
422
+ }