@amityco/social-plus-vise 0.8.1 → 0.12.2
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.
- package/CHANGELOG.md +207 -0
- package/README.md +107 -40
- package/dist/capabilities.js +447 -0
- package/dist/outcomes.js +463 -5
- package/dist/server.js +115 -3
- package/dist/tools/ast.js +25 -0
- package/dist/tools/compliance.js +88 -20
- package/dist/tools/debug.js +267 -0
- package/dist/tools/design.js +1496 -0
- package/dist/tools/docs.js +9 -4
- package/dist/tools/harness.js +17 -1
- package/dist/tools/integration.js +83 -7
- package/dist/tools/project.js +872 -67
- package/dist/tools/sdkVersion.js +129 -0
- package/dist/types.js +4 -0
- package/package.json +27 -6
- package/rules/auth.yaml +298 -38
- package/rules/comments.yaml +0 -72
- package/rules/feed.yaml +1151 -12
- package/rules/live-data.yaml +316 -36
- package/rules/push.yaml +140 -0
- package/rules/sdk-lifecycle.yaml +1428 -138
- package/rules/security.yaml +60 -0
- package/skills/social-plus-vise/SKILL.md +98 -55
- package/skills/social-plus-vise/reference/debugging.md +39 -0
- package/skills/social-plus-vise/reference/operations.md +59 -0
- package/skills/vise-harness-engineer/SKILL.md +35 -0
- package/social.plus-vise.png +0 -0
package/rules/live-data.yaml
CHANGED
|
@@ -8,10 +8,35 @@
|
|
|
8
8
|
"title": "Android live data observers must be cleaned up",
|
|
9
9
|
"severity": "warning",
|
|
10
10
|
"rationale": "Live Object and Live Collection observers should be disposed when their lifecycle owner ends.",
|
|
11
|
-
"applies_when": {
|
|
11
|
+
"applies_when": {
|
|
12
|
+
"platforms": [
|
|
13
|
+
"android"
|
|
14
|
+
],
|
|
15
|
+
"outcomes": [
|
|
16
|
+
"setup-live-data",
|
|
17
|
+
"add-feed",
|
|
18
|
+
"validate-setup"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
12
21
|
"enforcement": {
|
|
13
|
-
"deterministic": [
|
|
14
|
-
|
|
22
|
+
"deterministic": [
|
|
23
|
+
{
|
|
24
|
+
"check": "validator-finding-absent",
|
|
25
|
+
"finding_rule_id": "android.live.cleanup"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"attestation": {
|
|
29
|
+
"allowed": true,
|
|
30
|
+
"host_agent_min_confidence": "high",
|
|
31
|
+
"human_allowed": true,
|
|
32
|
+
"evidence_required": [
|
|
33
|
+
{
|
|
34
|
+
"field": "lifecycle_owner",
|
|
35
|
+
"description": "Lifecycle owner and cleanup location.",
|
|
36
|
+
"upload_policy": "upload-with-consent"
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
15
40
|
}
|
|
16
41
|
},
|
|
17
42
|
{
|
|
@@ -20,10 +45,35 @@
|
|
|
20
45
|
"title": "Flutter live data subscriptions must be cleaned up",
|
|
21
46
|
"severity": "warning",
|
|
22
47
|
"rationale": "Live Object and Live Collection subscriptions should be cancelled from dispose or equivalent cleanup.",
|
|
23
|
-
"applies_when": {
|
|
48
|
+
"applies_when": {
|
|
49
|
+
"platforms": [
|
|
50
|
+
"flutter"
|
|
51
|
+
],
|
|
52
|
+
"outcomes": [
|
|
53
|
+
"setup-live-data",
|
|
54
|
+
"add-feed",
|
|
55
|
+
"validate-setup"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
24
58
|
"enforcement": {
|
|
25
|
-
"deterministic": [
|
|
26
|
-
|
|
59
|
+
"deterministic": [
|
|
60
|
+
{
|
|
61
|
+
"check": "validator-finding-absent",
|
|
62
|
+
"finding_rule_id": "flutter.live.cleanup"
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
"attestation": {
|
|
66
|
+
"allowed": true,
|
|
67
|
+
"host_agent_min_confidence": "high",
|
|
68
|
+
"human_allowed": true,
|
|
69
|
+
"evidence_required": [
|
|
70
|
+
{
|
|
71
|
+
"field": "lifecycle_owner",
|
|
72
|
+
"description": "Lifecycle owner and cleanup location.",
|
|
73
|
+
"upload_policy": "upload-with-consent"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
27
77
|
}
|
|
28
78
|
},
|
|
29
79
|
{
|
|
@@ -32,10 +82,35 @@
|
|
|
32
82
|
"title": "TypeScript live data subscriptions must be cleaned up",
|
|
33
83
|
"severity": "warning",
|
|
34
84
|
"rationale": "Live Object and Live Collection subscriptions should be unsubscribed from the owning component, route, or store lifecycle.",
|
|
35
|
-
"applies_when": {
|
|
85
|
+
"applies_when": {
|
|
86
|
+
"platforms": [
|
|
87
|
+
"typescript"
|
|
88
|
+
],
|
|
89
|
+
"outcomes": [
|
|
90
|
+
"setup-live-data",
|
|
91
|
+
"add-feed",
|
|
92
|
+
"validate-setup"
|
|
93
|
+
]
|
|
94
|
+
},
|
|
36
95
|
"enforcement": {
|
|
37
|
-
"deterministic": [
|
|
38
|
-
|
|
96
|
+
"deterministic": [
|
|
97
|
+
{
|
|
98
|
+
"check": "validator-finding-absent",
|
|
99
|
+
"finding_rule_id": "typescript.live.cleanup"
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
"attestation": {
|
|
103
|
+
"allowed": true,
|
|
104
|
+
"host_agent_min_confidence": "high",
|
|
105
|
+
"human_allowed": true,
|
|
106
|
+
"evidence_required": [
|
|
107
|
+
{
|
|
108
|
+
"field": "lifecycle_owner",
|
|
109
|
+
"description": "Lifecycle owner and cleanup location.",
|
|
110
|
+
"upload_policy": "upload-with-consent"
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
39
114
|
}
|
|
40
115
|
},
|
|
41
116
|
{
|
|
@@ -44,10 +119,35 @@
|
|
|
44
119
|
"title": "React Native live data subscriptions must be cleaned up",
|
|
45
120
|
"severity": "warning",
|
|
46
121
|
"rationale": "Live Object and Live Collection subscriptions should be unsubscribed from the owning component, route, or store lifecycle.",
|
|
47
|
-
"applies_when": {
|
|
122
|
+
"applies_when": {
|
|
123
|
+
"platforms": [
|
|
124
|
+
"react-native"
|
|
125
|
+
],
|
|
126
|
+
"outcomes": [
|
|
127
|
+
"setup-live-data",
|
|
128
|
+
"add-feed",
|
|
129
|
+
"validate-setup"
|
|
130
|
+
]
|
|
131
|
+
},
|
|
48
132
|
"enforcement": {
|
|
49
|
-
"deterministic": [
|
|
50
|
-
|
|
133
|
+
"deterministic": [
|
|
134
|
+
{
|
|
135
|
+
"check": "validator-finding-absent",
|
|
136
|
+
"finding_rule_id": "react-native.live.cleanup"
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
"attestation": {
|
|
140
|
+
"allowed": true,
|
|
141
|
+
"host_agent_min_confidence": "high",
|
|
142
|
+
"human_allowed": true,
|
|
143
|
+
"evidence_required": [
|
|
144
|
+
{
|
|
145
|
+
"field": "lifecycle_owner",
|
|
146
|
+
"description": "Lifecycle owner and cleanup location.",
|
|
147
|
+
"upload_policy": "upload-with-consent"
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
}
|
|
51
151
|
}
|
|
52
152
|
},
|
|
53
153
|
{
|
|
@@ -56,10 +156,35 @@
|
|
|
56
156
|
"title": "iOS live data observers must be cleaned up",
|
|
57
157
|
"severity": "warning",
|
|
58
158
|
"rationale": "Live Object and Live Collection notification tokens should be invalidated when the view, controller, or owning object's lifecycle ends.",
|
|
59
|
-
"applies_when": {
|
|
159
|
+
"applies_when": {
|
|
160
|
+
"platforms": [
|
|
161
|
+
"ios"
|
|
162
|
+
],
|
|
163
|
+
"outcomes": [
|
|
164
|
+
"setup-live-data",
|
|
165
|
+
"add-feed",
|
|
166
|
+
"validate-setup"
|
|
167
|
+
]
|
|
168
|
+
},
|
|
60
169
|
"enforcement": {
|
|
61
|
-
"deterministic": [
|
|
62
|
-
|
|
170
|
+
"deterministic": [
|
|
171
|
+
{
|
|
172
|
+
"check": "validator-finding-absent",
|
|
173
|
+
"finding_rule_id": "ios.live.cleanup"
|
|
174
|
+
}
|
|
175
|
+
],
|
|
176
|
+
"attestation": {
|
|
177
|
+
"allowed": true,
|
|
178
|
+
"host_agent_min_confidence": "high",
|
|
179
|
+
"human_allowed": true,
|
|
180
|
+
"evidence_required": [
|
|
181
|
+
{
|
|
182
|
+
"field": "lifecycle_owner",
|
|
183
|
+
"description": "Lifecycle owner and cleanup location (deinit, viewWillDisappear, etc.).",
|
|
184
|
+
"upload_policy": "upload-with-consent"
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
63
188
|
}
|
|
64
189
|
},
|
|
65
190
|
{
|
|
@@ -68,11 +193,42 @@
|
|
|
68
193
|
"title": "Android list UIs should use reactive LiveCollections",
|
|
69
194
|
"severity": "warning",
|
|
70
195
|
"rationale": "Using one-shot Future-style queries for lists means the feed won't update when a new item is created. Use the reactive LiveCollection/observe API instead.",
|
|
71
|
-
"applies_when": {
|
|
196
|
+
"applies_when": {
|
|
197
|
+
"platforms": [
|
|
198
|
+
"android"
|
|
199
|
+
],
|
|
200
|
+
"outcomes": [
|
|
201
|
+
"add-feed",
|
|
202
|
+
"add-comments",
|
|
203
|
+
"add-chat",
|
|
204
|
+
"setup-live-data",
|
|
205
|
+
"validate-setup"
|
|
206
|
+
]
|
|
207
|
+
},
|
|
72
208
|
"enforcement": {
|
|
73
|
-
"deterministic": [
|
|
74
|
-
|
|
75
|
-
|
|
209
|
+
"deterministic": [
|
|
210
|
+
{
|
|
211
|
+
"check": "validator-finding-absent",
|
|
212
|
+
"finding_rule_id": "android.live-collection.api-mismatch"
|
|
213
|
+
}
|
|
214
|
+
],
|
|
215
|
+
"attestation": {
|
|
216
|
+
"allowed": true,
|
|
217
|
+
"host_agent_min_confidence": "high",
|
|
218
|
+
"human_allowed": true,
|
|
219
|
+
"evidence_required": [
|
|
220
|
+
{
|
|
221
|
+
"field": "query_lifetime",
|
|
222
|
+
"description": "Why a one-shot query is appropriate here (e.g. static search).",
|
|
223
|
+
"upload_policy": "upload-with-consent"
|
|
224
|
+
}
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"symptoms": [
|
|
229
|
+
"OutOfMemoryError",
|
|
230
|
+
"Subscription leak"
|
|
231
|
+
]
|
|
76
232
|
},
|
|
77
233
|
{
|
|
78
234
|
"id": "flutter.live-collection.api-mismatch",
|
|
@@ -80,11 +236,42 @@
|
|
|
80
236
|
"title": "Flutter list UIs should use reactive LiveCollections",
|
|
81
237
|
"severity": "warning",
|
|
82
238
|
"rationale": "Using one-shot Future-style queries for lists means the feed won't update when a new item is created. Use the reactive LiveCollection/listen API instead.",
|
|
83
|
-
"applies_when": {
|
|
239
|
+
"applies_when": {
|
|
240
|
+
"platforms": [
|
|
241
|
+
"flutter"
|
|
242
|
+
],
|
|
243
|
+
"outcomes": [
|
|
244
|
+
"add-feed",
|
|
245
|
+
"add-comments",
|
|
246
|
+
"add-chat",
|
|
247
|
+
"setup-live-data",
|
|
248
|
+
"validate-setup"
|
|
249
|
+
]
|
|
250
|
+
},
|
|
84
251
|
"enforcement": {
|
|
85
|
-
"deterministic": [
|
|
86
|
-
|
|
87
|
-
|
|
252
|
+
"deterministic": [
|
|
253
|
+
{
|
|
254
|
+
"check": "validator-finding-absent",
|
|
255
|
+
"finding_rule_id": "flutter.live-collection.api-mismatch"
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
"attestation": {
|
|
259
|
+
"allowed": true,
|
|
260
|
+
"host_agent_min_confidence": "high",
|
|
261
|
+
"human_allowed": true,
|
|
262
|
+
"evidence_required": [
|
|
263
|
+
{
|
|
264
|
+
"field": "query_lifetime",
|
|
265
|
+
"description": "Why a one-shot query is appropriate here.",
|
|
266
|
+
"upload_policy": "upload-with-consent"
|
|
267
|
+
}
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
"symptoms": [
|
|
272
|
+
"OutOfMemoryError",
|
|
273
|
+
"Subscription leak"
|
|
274
|
+
]
|
|
88
275
|
},
|
|
89
276
|
{
|
|
90
277
|
"id": "ios.live-collection.api-mismatch",
|
|
@@ -92,23 +279,85 @@
|
|
|
92
279
|
"title": "iOS list UIs should use reactive LiveCollections",
|
|
93
280
|
"severity": "warning",
|
|
94
281
|
"rationale": "Using one-shot Future-style queries for lists means the feed won't update when a new item is created. Use the reactive observe API instead.",
|
|
95
|
-
"applies_when": {
|
|
282
|
+
"applies_when": {
|
|
283
|
+
"platforms": [
|
|
284
|
+
"ios"
|
|
285
|
+
],
|
|
286
|
+
"outcomes": [
|
|
287
|
+
"add-feed",
|
|
288
|
+
"add-comments",
|
|
289
|
+
"add-chat",
|
|
290
|
+
"setup-live-data",
|
|
291
|
+
"validate-setup"
|
|
292
|
+
]
|
|
293
|
+
},
|
|
96
294
|
"enforcement": {
|
|
97
|
-
"deterministic": [
|
|
98
|
-
|
|
99
|
-
|
|
295
|
+
"deterministic": [
|
|
296
|
+
{
|
|
297
|
+
"check": "validator-finding-absent",
|
|
298
|
+
"finding_rule_id": "ios.live-collection.api-mismatch"
|
|
299
|
+
}
|
|
300
|
+
],
|
|
301
|
+
"attestation": {
|
|
302
|
+
"allowed": true,
|
|
303
|
+
"host_agent_min_confidence": "high",
|
|
304
|
+
"human_allowed": true,
|
|
305
|
+
"evidence_required": [
|
|
306
|
+
{
|
|
307
|
+
"field": "query_lifetime",
|
|
308
|
+
"description": "Why a one-shot query is appropriate here.",
|
|
309
|
+
"upload_policy": "upload-with-consent"
|
|
310
|
+
}
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
"symptoms": [
|
|
315
|
+
"OutOfMemoryError",
|
|
316
|
+
"Subscription leak"
|
|
317
|
+
]
|
|
100
318
|
},
|
|
101
319
|
{
|
|
102
320
|
"id": "typescript.live-collection.api-mismatch",
|
|
103
321
|
"version": 1,
|
|
104
322
|
"title": "TypeScript list UIs should use reactive LiveCollections",
|
|
105
323
|
"severity": "warning",
|
|
106
|
-
"rationale": "Using one-shot Promise-style queries for lists means the feed won't update when a new item is created. Use the reactive onData API instead.",
|
|
107
|
-
"applies_when": {
|
|
324
|
+
"rationale": "Using one-shot Promise-style queries for lists means the feed won't update when a new item is created. Use the reactive onData API instead, and preserve existing pagination/query wiring while converting the list to live updates.",
|
|
325
|
+
"applies_when": {
|
|
326
|
+
"platforms": [
|
|
327
|
+
"typescript"
|
|
328
|
+
],
|
|
329
|
+
"outcomes": [
|
|
330
|
+
"add-feed",
|
|
331
|
+
"add-comments",
|
|
332
|
+
"add-chat",
|
|
333
|
+
"setup-live-data",
|
|
334
|
+
"validate-setup"
|
|
335
|
+
]
|
|
336
|
+
},
|
|
108
337
|
"enforcement": {
|
|
109
|
-
"deterministic": [
|
|
110
|
-
|
|
111
|
-
|
|
338
|
+
"deterministic": [
|
|
339
|
+
{
|
|
340
|
+
"check": "validator-finding-absent",
|
|
341
|
+
"finding_rule_id": "typescript.live-collection.api-mismatch"
|
|
342
|
+
}
|
|
343
|
+
],
|
|
344
|
+
"attestation": {
|
|
345
|
+
"allowed": true,
|
|
346
|
+
"host_agent_min_confidence": "high",
|
|
347
|
+
"human_allowed": true,
|
|
348
|
+
"evidence_required": [
|
|
349
|
+
{
|
|
350
|
+
"field": "query_lifetime",
|
|
351
|
+
"description": "Why a one-shot query is appropriate here.",
|
|
352
|
+
"upload_policy": "upload-with-consent"
|
|
353
|
+
}
|
|
354
|
+
]
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
"symptoms": [
|
|
358
|
+
"OutOfMemoryError",
|
|
359
|
+
"Subscription leak"
|
|
360
|
+
]
|
|
112
361
|
},
|
|
113
362
|
{
|
|
114
363
|
"id": "react-native.live-collection.api-mismatch",
|
|
@@ -116,11 +365,42 @@
|
|
|
116
365
|
"title": "React Native list UIs should use reactive LiveCollections",
|
|
117
366
|
"severity": "warning",
|
|
118
367
|
"rationale": "Using one-shot Promise-style queries for lists means the feed won't update when a new item is created. Use the reactive onData API instead.",
|
|
119
|
-
"applies_when": {
|
|
368
|
+
"applies_when": {
|
|
369
|
+
"platforms": [
|
|
370
|
+
"react-native"
|
|
371
|
+
],
|
|
372
|
+
"outcomes": [
|
|
373
|
+
"add-feed",
|
|
374
|
+
"add-comments",
|
|
375
|
+
"add-chat",
|
|
376
|
+
"setup-live-data",
|
|
377
|
+
"validate-setup"
|
|
378
|
+
]
|
|
379
|
+
},
|
|
120
380
|
"enforcement": {
|
|
121
|
-
"deterministic": [
|
|
122
|
-
|
|
123
|
-
|
|
381
|
+
"deterministic": [
|
|
382
|
+
{
|
|
383
|
+
"check": "validator-finding-absent",
|
|
384
|
+
"finding_rule_id": "react-native.live-collection.api-mismatch"
|
|
385
|
+
}
|
|
386
|
+
],
|
|
387
|
+
"attestation": {
|
|
388
|
+
"allowed": true,
|
|
389
|
+
"host_agent_min_confidence": "high",
|
|
390
|
+
"human_allowed": true,
|
|
391
|
+
"evidence_required": [
|
|
392
|
+
{
|
|
393
|
+
"field": "query_lifetime",
|
|
394
|
+
"description": "Why a one-shot query is appropriate here.",
|
|
395
|
+
"upload_policy": "upload-with-consent"
|
|
396
|
+
}
|
|
397
|
+
]
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
"symptoms": [
|
|
401
|
+
"OutOfMemoryError",
|
|
402
|
+
"Subscription leak"
|
|
403
|
+
]
|
|
124
404
|
}
|
|
125
405
|
]
|
|
126
406
|
}
|
package/rules/push.yaml
CHANGED
|
@@ -541,6 +541,146 @@
|
|
|
541
541
|
]
|
|
542
542
|
}
|
|
543
543
|
}
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
"id": "react-native.push.apns-token-before-fcm",
|
|
547
|
+
"version": 1,
|
|
548
|
+
"title": "React Native iOS must retrieve APNs token before fetching FCM token",
|
|
549
|
+
"severity": "warning",
|
|
550
|
+
"rationale": "On iOS, calling Firebase messaging().getToken() before the APNs token is registered with Firebase yields an error or generates an invalid FCM token. You must retrieve the APNs token first by calling messaging().getAPNSToken() and ensuring it is available before requesting the FCM token.",
|
|
551
|
+
"feedforward": "You MUST verify that messaging().getAPNSToken() is called and returns a valid token before calling messaging().getToken() on iOS.",
|
|
552
|
+
"applies_when": {
|
|
553
|
+
"platforms": [
|
|
554
|
+
"react-native"
|
|
555
|
+
],
|
|
556
|
+
"outcomes": [
|
|
557
|
+
"setup-push",
|
|
558
|
+
"validate-setup"
|
|
559
|
+
]
|
|
560
|
+
},
|
|
561
|
+
"enforcement": {
|
|
562
|
+
"inferential": {
|
|
563
|
+
"prompt": "Review the React Native Push Notification setup. Does the code ensure messaging().getAPNSToken() successfully returns a token on iOS before calling messaging().getToken()?",
|
|
564
|
+
"target_signer": "host-agent"
|
|
565
|
+
},
|
|
566
|
+
"attestation": {
|
|
567
|
+
"allowed": true,
|
|
568
|
+
"host_agent_min_confidence": "high",
|
|
569
|
+
"human_allowed": true,
|
|
570
|
+
"evidence_required": [
|
|
571
|
+
{
|
|
572
|
+
"field": "apns_token_check",
|
|
573
|
+
"description": "How the application ensures the APNs token is fetched and verified on iOS before requesting the FCM token.",
|
|
574
|
+
"upload_policy": "upload-with-consent"
|
|
575
|
+
}
|
|
576
|
+
]
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
"id": "ios.push.apns-credentials-configured",
|
|
582
|
+
"version": 1,
|
|
583
|
+
"title": "iOS APNs credentials must be correctly configured and uploaded",
|
|
584
|
+
"severity": "warning",
|
|
585
|
+
"rationale": "To deliver push notifications to iOS devices, Apple Push Notification service (APNs) credentials (.p12 certificate or .p8 private key) must be generated on the Apple Developer portal and uploaded to the Amity Admin Console. When generating credentials, selecting 'Apple Push Notification service SSL (Sandbox & Production)' ensures a single certificate covers both development and production. If your architecture uses a Firebase FCM bridge, the APNs private key or certificate must also be uploaded to the Firebase Console, and credentials must not be expired.",
|
|
586
|
+
"feedforward": "You MUST upload a valid, non-expired APNs certificate (.p12) or private key (.p8) to the Amity Admin Console, ensuring it is generated as 'Apple Push Notification service SSL (Sandbox & Production)'. If using the FCM bridge, you MUST also upload the APNs key to your Firebase project settings.",
|
|
587
|
+
"applies_when": {
|
|
588
|
+
"platforms": [
|
|
589
|
+
"ios"
|
|
590
|
+
],
|
|
591
|
+
"outcomes": [
|
|
592
|
+
"setup-push",
|
|
593
|
+
"validate-setup"
|
|
594
|
+
]
|
|
595
|
+
},
|
|
596
|
+
"enforcement": {
|
|
597
|
+
"inferential": {
|
|
598
|
+
"prompt": "Review the iOS Push Notification integration. Has a Sandbox & Production APNs credential (.p12 or .p8) been uploaded to the Amity Admin Console? If using FCM, has the APNs key also been uploaded to Firebase?",
|
|
599
|
+
"target_signer": "host-agent"
|
|
600
|
+
},
|
|
601
|
+
"attestation": {
|
|
602
|
+
"allowed": true,
|
|
603
|
+
"host_agent_min_confidence": "high",
|
|
604
|
+
"human_allowed": true,
|
|
605
|
+
"evidence_required": [
|
|
606
|
+
{
|
|
607
|
+
"field": "credentials_upload_verification",
|
|
608
|
+
"description": "Evidence or confirmation of the Sandbox & Production APNs credentials uploaded to the Amity Admin Console (and Firebase if using FCM).",
|
|
609
|
+
"upload_policy": "upload-with-consent"
|
|
610
|
+
}
|
|
611
|
+
]
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
"id": "ios.push.app-entitlements-enabled",
|
|
617
|
+
"version": 1,
|
|
618
|
+
"title": "iOS application capability and App ID must match push credentials",
|
|
619
|
+
"severity": "warning",
|
|
620
|
+
"rationale": "Push notifications require the Push Notifications capability to be enabled in the Xcode project (under Signing & Capabilities). In addition, the App ID/Bundle ID of the iOS application must match the Bundle ID associated with the uploaded APNs certificate or key.",
|
|
621
|
+
"feedforward": "You MUST enable the 'Push Notifications' capability in Xcode and verify that the application's Bundle ID matches the App ID of the uploaded APNs certificate.",
|
|
622
|
+
"applies_when": {
|
|
623
|
+
"platforms": [
|
|
624
|
+
"ios"
|
|
625
|
+
],
|
|
626
|
+
"outcomes": [
|
|
627
|
+
"setup-push",
|
|
628
|
+
"validate-setup"
|
|
629
|
+
]
|
|
630
|
+
},
|
|
631
|
+
"enforcement": {
|
|
632
|
+
"inferential": {
|
|
633
|
+
"prompt": "Review the Xcode project configuration. Is the 'Push Notifications' capability enabled under Signing & Capabilities, and does the Bundle ID match the uploaded APNs credentials?",
|
|
634
|
+
"target_signer": "host-agent"
|
|
635
|
+
},
|
|
636
|
+
"attestation": {
|
|
637
|
+
"allowed": true,
|
|
638
|
+
"host_agent_min_confidence": "high",
|
|
639
|
+
"human_allowed": true,
|
|
640
|
+
"evidence_required": [
|
|
641
|
+
{
|
|
642
|
+
"field": "entitlements_verification",
|
|
643
|
+
"description": "Details showing the enabled Push Notifications capability and Bundle ID in the Xcode project settings.",
|
|
644
|
+
"upload_policy": "upload-with-consent"
|
|
645
|
+
}
|
|
646
|
+
]
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"id": "ios.push.testing-environment-requirements",
|
|
652
|
+
"version": 1,
|
|
653
|
+
"title": "iOS push notifications must be tested on a real device with proper build configuration",
|
|
654
|
+
"severity": "warning",
|
|
655
|
+
"rationale": "Apple does not support receiving remote push notifications on the iOS Simulator; testing must be performed on a physical iOS device. When testing with a production APNs certificate, the app must be a production/TestFlight build. Additionally, user notification permissions must be explicitly granted, and the device must not be in Do Not Disturb (DND) or Focus mode, as these OS states suppress notification delivery.",
|
|
656
|
+
"feedforward": "You MUST test remote push notifications on a physical iOS device (not the simulator) using a TestFlight or App Store build when testing production certificates. Verify that the user has granted notification permissions and the device is not in Do Not Disturb or Focus mode.",
|
|
657
|
+
"applies_when": {
|
|
658
|
+
"platforms": [
|
|
659
|
+
"ios"
|
|
660
|
+
],
|
|
661
|
+
"outcomes": [
|
|
662
|
+
"setup-push",
|
|
663
|
+
"validate-setup"
|
|
664
|
+
]
|
|
665
|
+
},
|
|
666
|
+
"enforcement": {
|
|
667
|
+
"inferential": {
|
|
668
|
+
"prompt": "Review the push notification testing setup. Is verification performed on a physical iOS device using a TestFlight/production build (for production certs) with granted notifications permissions and Focus/DND mode off?",
|
|
669
|
+
"target_signer": "host-agent"
|
|
670
|
+
},
|
|
671
|
+
"attestation": {
|
|
672
|
+
"allowed": true,
|
|
673
|
+
"host_agent_min_confidence": "high",
|
|
674
|
+
"human_allowed": true,
|
|
675
|
+
"evidence_required": [
|
|
676
|
+
{
|
|
677
|
+
"field": "testing_setup_verification",
|
|
678
|
+
"description": "Confirmation of testing on a real device, build configuration (production/TestFlight for prod cert), user permission check, and Focus/DND check.",
|
|
679
|
+
"upload_policy": "upload-with-consent"
|
|
680
|
+
}
|
|
681
|
+
]
|
|
682
|
+
}
|
|
683
|
+
}
|
|
544
684
|
}
|
|
545
685
|
]
|
|
546
686
|
}
|