swipium 1.1.0 → 1.3.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.
Files changed (109) hide show
  1. package/README.md +14 -9
  2. package/THREAT_MODEL.md +59 -0
  3. package/dist/appMap/diff.js +60 -0
  4. package/dist/appMap/diff.js.map +1 -0
  5. package/dist/appMap/featureIndex.js +183 -0
  6. package/dist/appMap/featureIndex.js.map +1 -0
  7. package/dist/automation/capabilities.js +167 -0
  8. package/dist/automation/capabilities.js.map +1 -0
  9. package/dist/automation/gestures.js +94 -0
  10. package/dist/automation/gestures.js.map +1 -0
  11. package/dist/automation/maestroIr.js +282 -0
  12. package/dist/automation/maestroIr.js.map +1 -0
  13. package/dist/automation/plan.js +268 -0
  14. package/dist/automation/plan.js.map +1 -0
  15. package/dist/automation/report.js +83 -0
  16. package/dist/automation/report.js.map +1 -0
  17. package/dist/automation/selectors.js +201 -0
  18. package/dist/automation/selectors.js.map +1 -0
  19. package/dist/automation/types.js +13 -0
  20. package/dist/automation/types.js.map +1 -0
  21. package/dist/automation/waits.js +91 -0
  22. package/dist/automation/waits.js.map +1 -0
  23. package/dist/automation/webview.js +81 -0
  24. package/dist/automation/webview.js.map +1 -0
  25. package/dist/featureTesting/executionBootstrap.js +14 -10
  26. package/dist/featureTesting/executionBootstrap.js.map +1 -1
  27. package/dist/featureTesting/featureMap.js +53 -0
  28. package/dist/featureTesting/featureMap.js.map +1 -0
  29. package/dist/featureTesting/featureScope.js +354 -0
  30. package/dist/featureTesting/featureScope.js.map +1 -0
  31. package/dist/featureTesting/mapFeatureScope.js +143 -0
  32. package/dist/featureTesting/mapFeatureScope.js.map +1 -0
  33. package/dist/featureTesting/objectiveModel.js +129 -0
  34. package/dist/featureTesting/objectiveModel.js.map +1 -0
  35. package/dist/featureTesting/resultMerge.js +112 -0
  36. package/dist/featureTesting/resultMerge.js.map +1 -0
  37. package/dist/featureTesting/sources.js +96 -0
  38. package/dist/featureTesting/sources.js.map +1 -0
  39. package/dist/featureTesting/suiteBridge.js +51 -0
  40. package/dist/featureTesting/suiteBridge.js.map +1 -0
  41. package/dist/featureTesting/synonyms.js +73 -0
  42. package/dist/featureTesting/synonyms.js.map +1 -0
  43. package/dist/featureTesting/testCaseFactory.js +107 -0
  44. package/dist/featureTesting/testCaseFactory.js.map +1 -0
  45. package/dist/featureTesting/testPlan.js +50 -0
  46. package/dist/featureTesting/testPlan.js.map +1 -0
  47. package/dist/flows/repair.js +363 -0
  48. package/dist/flows/repair.js.map +1 -0
  49. package/dist/interop/maestro.js +151 -0
  50. package/dist/interop/maestro.js.map +1 -0
  51. package/dist/mobileAudit/checks.js +251 -0
  52. package/dist/mobileAudit/checks.js.map +1 -0
  53. package/dist/mobileAudit/evidence.js +49 -0
  54. package/dist/mobileAudit/evidence.js.map +1 -0
  55. package/dist/mobileAudit/profiles.js +73 -0
  56. package/dist/mobileAudit/profiles.js.map +1 -0
  57. package/dist/mobileAudit/results.js +41 -0
  58. package/dist/mobileAudit/results.js.map +1 -0
  59. package/dist/mobileAudit/runner.js +229 -0
  60. package/dist/mobileAudit/runner.js.map +1 -0
  61. package/dist/oracle/locator.js +177 -0
  62. package/dist/oracle/locator.js.map +1 -0
  63. package/dist/server.js +31 -0
  64. package/dist/server.js.map +1 -1
  65. package/dist/testSuite/exporter.js +70 -0
  66. package/dist/testSuite/exporter.js.map +1 -0
  67. package/dist/testSuite/lint.js +53 -0
  68. package/dist/testSuite/lint.js.map +1 -0
  69. package/dist/tools/build.js +172 -0
  70. package/dist/tools/build.js.map +1 -0
  71. package/dist/tools/bundletool.js +145 -0
  72. package/dist/tools/bundletool.js.map +1 -0
  73. package/dist/tools/capabilities.js +66 -4
  74. package/dist/tools/capabilities.js.map +1 -1
  75. package/dist/tools/featureTesting.js +344 -0
  76. package/dist/tools/featureTesting.js.map +1 -0
  77. package/dist/tools/flow.js +67 -1
  78. package/dist/tools/flow.js.map +1 -1
  79. package/dist/tools/flowRepair.js +66 -0
  80. package/dist/tools/flowRepair.js.map +1 -0
  81. package/dist/tools/idling.js +104 -0
  82. package/dist/tools/idling.js.map +1 -0
  83. package/dist/tools/inputCapabilities.js +30 -0
  84. package/dist/tools/inputCapabilities.js.map +1 -0
  85. package/dist/tools/issues.js +218 -0
  86. package/dist/tools/issues.js.map +1 -0
  87. package/dist/tools/jobs.js +12 -1
  88. package/dist/tools/jobs.js.map +1 -1
  89. package/dist/tools/locator.js +57 -0
  90. package/dist/tools/locator.js.map +1 -0
  91. package/dist/tools/maestro.js +78 -0
  92. package/dist/tools/maestro.js.map +1 -0
  93. package/dist/tools/mobileAudit.js +115 -0
  94. package/dist/tools/mobileAudit.js.map +1 -0
  95. package/dist/tools/resolveArtifact.js +80 -0
  96. package/dist/tools/resolveArtifact.js.map +1 -0
  97. package/dist/tools/resolveTarget.js +67 -0
  98. package/dist/tools/resolveTarget.js.map +1 -0
  99. package/dist/tools/suite.js +49 -1
  100. package/dist/tools/suite.js.map +1 -1
  101. package/dist/tools/testSuite.js +233 -0
  102. package/dist/tools/testSuite.js.map +1 -0
  103. package/dist/tools/wait.js +58 -0
  104. package/dist/tools/wait.js.map +1 -0
  105. package/dist/version.js +41 -2
  106. package/dist/version.js.map +1 -1
  107. package/docs/mcp-server.md +1 -1
  108. package/docs/tools.md +86 -3
  109. package/package.json +3 -2
@@ -0,0 +1,251 @@
1
+ // SWIPIUM-REQ-08 — executable mobile-audit checks. Each check observes the device through the
2
+ // Driver + evidence helpers and returns an honest result: it only reports `pass` when Swipium
3
+ // actually observed the evidence; otherwise `blocked`/`not_applicable`/`skipped`/`fail`. The runner
4
+ // (runner.ts) wraps these with id/title/profile and records issues for fail/blocked outcomes.
5
+ //
6
+ // Checks never purchase, bypass OTP, delete real accounts, or tap unknown external links.
7
+ import { rankCandidates } from '../explore/candidates.js';
8
+ import { allowsControlledLogout } from '../explore/policy.js';
9
+ import { parseSnapshot } from '../snapshot/parse.js';
10
+ import { captureScreenshot, foreground, health, snapshotText } from './evidence.js';
11
+ const ok = (reason, evidenceUris = []) => ({ status: 'pass', reason, evidenceUris });
12
+ const na = (reason) => ({ status: 'not_applicable', reason, evidenceUris: [] });
13
+ const skip = (reason) => ({ status: 'skipped', reason, evidenceUris: [] });
14
+ // ---- smoke ---------------------------------------------------------------------------------
15
+ export async function checkLaunch(ctx) {
16
+ if (!ctx.appId)
17
+ return skip('no app id known — cannot drive launch; relying on the current foreground app');
18
+ try {
19
+ await ctx.driver.terminateApp(ctx.appId).catch(() => { });
20
+ await ctx.driver.launchApp(ctx.appId);
21
+ }
22
+ catch (e) {
23
+ return { status: 'fail', category: 'app_bug', severity: 'blocker', reason: `app failed to launch: ${String(e.message ?? e)}`, evidenceUris: [], nextStep: 'Confirm the app is installed and (for debug builds) Metro is reachable.' };
24
+ }
25
+ const fg = await foreground(ctx);
26
+ const shot = await captureScreenshot(ctx, 'audit launch');
27
+ const evidence = shot ? [shot] : [];
28
+ if (fg && ctx.appId && fg.includes(ctx.appId.split('/')[0]))
29
+ return ok(`launched, foreground=${fg}`, evidence);
30
+ return { status: 'fail', category: 'app_bug', severity: 'high', reason: `expected ${ctx.appId} foreground, saw ${fg}`, evidenceUris: evidence };
31
+ }
32
+ export async function checkHealthScan(ctx) {
33
+ const h = await health(ctx);
34
+ const shot = await captureScreenshot(ctx, 'audit health');
35
+ const evidence = shot ? [shot] : [];
36
+ if (!h.nativeHealthy) {
37
+ const crash = h.nativeStatus === 'native_crash' || h.nativeStatus === 'anr';
38
+ return { status: 'fail', category: 'blocker_app_bug', severity: 'blocker', reason: `native ${h.nativeStatus}`, evidenceUris: evidence, nextStep: crash ? 'Capture the crash/ANR log and fix it; do not blindly retry.' : undefined };
39
+ }
40
+ if (h.appStatus === 'error')
41
+ return { status: 'fail', category: 'blocker_app_bug', severity: 'blocker', reason: 'app error surface (RedBox/error boundary)', evidenceUris: evidence };
42
+ if (h.appStatus === 'degraded')
43
+ return { status: 'fail', category: 'app_bug', severity: 'medium', reason: 'recoverable app warning (LogBox)', evidenceUris: evidence };
44
+ return ok(`healthy (foreground=${h.foreground})`, evidence);
45
+ }
46
+ export async function checkNavigation(ctx) {
47
+ let xml = '';
48
+ try {
49
+ xml = await ctx.driver.dumpXml();
50
+ }
51
+ catch {
52
+ return skip('no UI tree available to evaluate navigation');
53
+ }
54
+ let elements;
55
+ try {
56
+ elements = parseSnapshot(xml).allNodes.map((n, i) => ({ ref: `@n${i}`, role: n.cls, label: n.desc || undefined, text: n.text || undefined, id: n.id || undefined, clickable: n.clickable === true, bounds: n.bounds }));
57
+ }
58
+ catch {
59
+ return skip('could not parse the UI tree');
60
+ }
61
+ const candidates = rankCandidates(elements);
62
+ const safe = candidates.find((c) => c.risk === 'safe' && c.bounds);
63
+ if (!safe || !safe.bounds)
64
+ return skip('no safe navigation control found on this screen');
65
+ const before = await foreground(ctx);
66
+ try {
67
+ await ctx.driver.tapXY(Math.round(safe.bounds.x + safe.bounds.w / 2), Math.round(safe.bounds.y + safe.bounds.h / 2));
68
+ }
69
+ catch {
70
+ return skip('navigation tap not supported on this backend');
71
+ }
72
+ const h = await health(ctx);
73
+ if (!h.healthy)
74
+ return { status: 'fail', category: 'app_bug', severity: 'high', reason: `navigation tap "${safe.label ?? ''}" produced ${h.nativeStatus}/${h.appStatus}`, evidenceUris: [] };
75
+ const after = await foreground(ctx);
76
+ return ok(`navigated safely via "${safe.label ?? safe.locator?.value ?? 'control'}" (${before}→${after})`);
77
+ }
78
+ // ---- store compliance ----------------------------------------------------------------------
79
+ function found(text, ...needles) {
80
+ return needles.some((n) => text.includes(n));
81
+ }
82
+ export async function checkPrivacyLink(ctx, text) {
83
+ const shot = await captureScreenshot(ctx, 'audit privacy');
84
+ if (found(text, 'privacy policy', 'privacy notice'))
85
+ return ok('Privacy Policy surface found', shot ? [shot] : []);
86
+ return { status: 'fail', category: 'store_compliance', severity: 'high', reason: 'no Privacy Policy link found on the inspected screens', evidenceUris: shot ? [shot] : [], nextStep: 'Expose a Privacy Policy link (required for app stores).' };
87
+ }
88
+ export async function checkTermsLink(ctx, text) {
89
+ const shot = await captureScreenshot(ctx, 'audit terms');
90
+ if (found(text, 'terms of service', 'terms of use', 'terms and conditions', 'terms'))
91
+ return ok('Terms surface found', shot ? [shot] : []);
92
+ return { status: 'fail', category: 'store_compliance', severity: 'medium', reason: 'no Terms link found on the inspected screens', evidenceUris: shot ? [shot] : [] };
93
+ }
94
+ export async function checkAccountDeletion(ctx, text) {
95
+ const hasAccountContext = found(text, 'account', 'profile', 'sign out', 'log out', 'settings');
96
+ if (!hasAccountContext)
97
+ return na('no account/profile surface observed — account deletion not applicable here');
98
+ if (found(text, 'delete account', 'delete your account', 'data deletion', 'close account', 'remove account'))
99
+ return ok('account deletion / data-deletion path found');
100
+ return { status: 'fail', category: 'store_compliance', severity: 'high', reason: 'account surface present but no delete-account / data-deletion path found', evidenceUris: [], nextStep: 'Expose an account/data deletion flow (required where the app has accounts).' };
101
+ }
102
+ export async function checkSubscriptionManagement(ctx, text) {
103
+ const hasSub = found(text, 'subscribe', 'subscription', 'premium', 'free trial', 'upgrade');
104
+ if (!hasSub)
105
+ return na('no subscription/paywall surface observed');
106
+ if (found(text, 'restore purchase', 'restore purchases', 'manage subscription', 'manage your subscription'))
107
+ return ok('restore / manage-subscription path found');
108
+ return { status: 'fail', category: 'store_compliance', severity: 'medium', reason: 'subscription surface present but no restore-purchase / manage-subscription path found', evidenceUris: [] };
109
+ }
110
+ export async function checkPaywall(ctx, text) {
111
+ const isPaywall = found(text, 'subscribe', 'free trial', 'start trial', 'unlock premium', 'upgrade to');
112
+ if (!isPaywall)
113
+ return na('no paywall observed');
114
+ const hasFreePath = found(text, 'not now', 'maybe later', 'skip', 'continue free', 'no thanks', 'close', 'dismiss');
115
+ if (hasFreePath)
116
+ return ok('soft paywall with a free/dismiss path');
117
+ return { status: 'blocked', category: 'hard_gate', severity: 'medium', reason: 'hard paywall with no permitted test path — recorded without purchase', evidenceUris: [], nextStep: 'A hard gate stops only this workflow, not the whole run.' };
118
+ }
119
+ export function checkExternalLinks() {
120
+ return skip('external links are not auto-opened for safety — verify manually');
121
+ }
122
+ // ---- resilience ----------------------------------------------------------------------------
123
+ const OFFLINE_COPY = ['no internet', 'no connection', 'offline', 'check your connection', 'network unavailable', 'no network'];
124
+ export async function checkOfflineEntry(ctx) {
125
+ try {
126
+ await ctx.driver.setAirplane(true);
127
+ }
128
+ catch {
129
+ return { status: 'blocked', reason: 'network manipulation unavailable on this backend', evidenceUris: [] };
130
+ }
131
+ const h = await health(ctx);
132
+ const text = await snapshotText(ctx);
133
+ const shot = await captureScreenshot(ctx, 'audit offline');
134
+ const evidence = shot ? [shot] : [];
135
+ if (!h.healthy)
136
+ return { status: 'fail', category: 'app_bug', severity: 'high', reason: `app unhealthy offline (${h.nativeStatus}/${h.appStatus})`, evidenceUris: evidence };
137
+ if (found(text, ...OFFLINE_COPY))
138
+ return ok('app shows an expected offline state', evidence);
139
+ return ok('app stayed healthy offline (no explicit offline message observed)', evidence);
140
+ }
141
+ export async function checkNetworkRestoration(ctx) {
142
+ try {
143
+ await ctx.driver.setAirplane(false);
144
+ }
145
+ catch {
146
+ return { status: 'blocked', reason: 'network manipulation unavailable on this backend', evidenceUris: [] };
147
+ }
148
+ const h = await health(ctx);
149
+ if (!h.healthy)
150
+ return { status: 'fail', category: 'app_bug', severity: 'high', reason: `app did not recover after connectivity returned (${h.nativeStatus}/${h.appStatus})`, evidenceUris: [] };
151
+ return ok('app recovered after network restoration');
152
+ }
153
+ export async function checkProcessRelaunch(ctx) {
154
+ if (!ctx.appId)
155
+ return skip('no app id known — cannot drive a kill/relaunch');
156
+ try {
157
+ await ctx.driver.terminateApp(ctx.appId);
158
+ await ctx.driver.launchApp(ctx.appId);
159
+ }
160
+ catch (e) {
161
+ return { status: 'fail', category: 'app_bug', severity: 'high', reason: `relaunch failed: ${String(e.message ?? e)}`, evidenceUris: [] };
162
+ }
163
+ const h = await health(ctx);
164
+ const shot = await captureScreenshot(ctx, 'audit relaunch');
165
+ if (!h.healthy)
166
+ return { status: 'fail', category: 'app_bug', severity: 'high', reason: `app unhealthy after relaunch (${h.nativeStatus}/${h.appStatus})`, evidenceUris: shot ? [shot] : [] };
167
+ return ok('app returned to a sane state after kill/relaunch', shot ? [shot] : []);
168
+ }
169
+ export function checkRotation() {
170
+ return skip('rotation is not driven automatically — verify manually where supported');
171
+ }
172
+ /**
173
+ * Find and tap a "Log out" control on the current screen, gated by the controlled account-cycle
174
+ * policy (logout permitted only on a disposable account; delete/pay/send stay refused). Returns the
175
+ * post-logout screen text so the caller can check the forgot-password entrypoint on the LOGGED-OUT
176
+ * surface — without a full exploration that would auto-re-login via stored credentials.
177
+ */
178
+ export async function findAndTapLogout(ctx, disposableAccount) {
179
+ let xml = '';
180
+ try {
181
+ xml = await ctx.driver.dumpXml();
182
+ }
183
+ catch {
184
+ return { tapped: false, loggedOutText: '', authSurface: false };
185
+ }
186
+ let nodes;
187
+ try {
188
+ nodes = parseSnapshot(xml).allNodes;
189
+ }
190
+ catch {
191
+ return { tapped: false, loggedOutText: '', authSurface: false };
192
+ }
193
+ const logout = nodes.find((n) => n.clickable && /log\s?out|sign\s?out/i.test(`${n.text} ${n.desc} ${n.id}`));
194
+ if (!logout)
195
+ return { tapped: false, loggedOutText: await snapshotText(ctx), authSurface: false };
196
+ // Controlled exception: only a genuine logout, only on a disposable account.
197
+ if (!allowsControlledLogout({ label: logout.text || logout.desc, id: logout.id }, { accountCycle: true, disposableAccount })) {
198
+ return { tapped: false, loggedOutText: await snapshotText(ctx), authSurface: false };
199
+ }
200
+ const [x1, y1, x2, y2] = logout.bounds;
201
+ try {
202
+ await ctx.driver.tapXY(Math.round((x1 + x2) / 2), Math.round((y1 + y2) / 2));
203
+ }
204
+ catch {
205
+ return { tapped: false, loggedOutText: await snapshotText(ctx), authSurface: false };
206
+ }
207
+ const loggedOutText = await snapshotText(ctx);
208
+ const authSurface = /sign\s?in|log\s?in|email|password|username|forgot|create account/.test(loggedOutText);
209
+ return { tapped: true, loggedOutText, authSurface };
210
+ }
211
+ /**
212
+ * Evaluate the forgot-password entrypoint from the LOGGED-OUT auth surface (captured right after
213
+ * logout, before any re-login). Pass when a forgot/reset link is present; a confirmed login screen
214
+ * without one is an improvement; if logout couldn't reach an auth surface, return blocked rather than
215
+ * falsely failing (REQ-08 account-cycle bug fix).
216
+ */
217
+ export function checkForgotPassword(loggedOutText) {
218
+ const isAuthSurface = /sign\s?in|log\s?in|email|password|username|forgot|create account/.test(loggedOutText);
219
+ const hasForgot = /forgot.?password|reset.?password|forgot your password|trouble signing in/.test(loggedOutText);
220
+ if (hasForgot)
221
+ return { status: 'pass', reason: 'forgot-password entrypoint is present on the logged-out auth surface (not exercised — Swipium never consumes email/OTP)', evidenceUris: [], workflow: 'account_cycle' };
222
+ if (isAuthSurface)
223
+ return { status: 'fail', category: 'improvement', severity: 'low', reason: 'no forgot-password entrypoint on the logged-out login screen', evidenceUris: [], workflow: 'account_cycle', nextStep: 'Add a forgot/reset-password entrypoint on the login screen.' };
224
+ return { status: 'blocked', reason: 'logout not confirmed — could not reach the logged-out auth surface to check the forgot-password entrypoint', evidenceUris: [], workflow: 'account_cycle' };
225
+ }
226
+ // ---- readiness -----------------------------------------------------------------------------
227
+ export async function checkLocatorReadiness(ctx) {
228
+ let xml = '';
229
+ try {
230
+ xml = await ctx.driver.dumpXml();
231
+ }
232
+ catch {
233
+ return skip('no UI tree available to assess locator readiness');
234
+ }
235
+ let nodes;
236
+ try {
237
+ nodes = parseSnapshot(xml).allNodes;
238
+ }
239
+ catch {
240
+ return skip('could not parse the UI tree');
241
+ }
242
+ const clickable = nodes.filter((n) => n.clickable === true);
243
+ if (clickable.length === 0)
244
+ return skip('no interactive controls on this screen');
245
+ const durable = clickable.filter((n) => n.id || n.desc);
246
+ const pct = Math.round((durable.length / clickable.length) * 100);
247
+ if (pct >= 70)
248
+ return ok(`${pct}% of interactive controls have durable locators`);
249
+ return { status: 'fail', category: 'accessibility_readiness', severity: 'low', reason: `only ${pct}% of interactive controls have durable locators (testID/accessibility id)`, evidenceUris: [], nextStep: 'Add accessibility identifiers / testIDs to important controls.' };
250
+ }
251
+ //# sourceMappingURL=checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.js","sourceRoot":"","sources":["../../src/mobileAudit/checks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ // SWIPIUM-REQ-08 — evidence + observation helpers for the executable mobile audit.
2
+ //
3
+ // Thin wrappers over the Driver + SessionStore so audit checks can capture a screenshot, read the
4
+ // current screen's visible text, and run a health check without each check duplicating that plumbing.
5
+ // Sensitive-mode aware (no pixels when session.sensitive). Best-effort — never throws.
6
+ import { parseSnapshot } from '../snapshot/parse.js';
7
+ import { checkHealth } from '../oracle/health.js';
8
+ /** Capture an evidence screenshot (sensitive-mode aware). Returns the artifact URI or undefined. */
9
+ export async function captureScreenshot(ctx, label) {
10
+ if (ctx.session.sensitive)
11
+ return undefined;
12
+ try {
13
+ const png = await ctx.driver.screenshot();
14
+ return ctx.sessions.saveArtifact(ctx.session, 'screenshot', `audit-${Date.now()}.png`, png, 'image/png', label);
15
+ }
16
+ catch {
17
+ return undefined;
18
+ }
19
+ }
20
+ /** Read the current screen's visible text (lowercased, joined). Best-effort → '' on failure. */
21
+ export async function snapshotText(ctx) {
22
+ try {
23
+ const xml = await ctx.driver.dumpXml();
24
+ if (!xml)
25
+ return '';
26
+ const nodes = parseSnapshot(xml).allNodes;
27
+ return nodes
28
+ .map((n) => `${n.text ?? ''} ${n.desc ?? ''} ${n.id ?? ''}`)
29
+ .join(' ')
30
+ .toLowerCase();
31
+ }
32
+ catch {
33
+ return '';
34
+ }
35
+ }
36
+ /** Run a health check on the current screen. */
37
+ export async function health(ctx) {
38
+ return checkHealth(ctx.driver, ctx.appId);
39
+ }
40
+ /** Current foreground app/owner. Best-effort → 'unknown'. */
41
+ export async function foreground(ctx) {
42
+ try {
43
+ return await ctx.driver.foregroundOwner();
44
+ }
45
+ catch {
46
+ return 'unknown';
47
+ }
48
+ }
49
+ //# sourceMappingURL=evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/mobileAudit/evidence.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,EAAE;AACF,kGAAkG;AAClG,sGAAsG;AACtG,uFAAuF;AAEvF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAqB,MAAM,qBAAqB,CAAC;AAWrE,oGAAoG;AACpG,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAqB,EAAE,KAAa;IAC1E,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QAC1C,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;IAClH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAqB;IACtD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACvC,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC1C,OAAO,KAAK;aACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;aAC3D,IAAI,CAAC,IAAI,CAAC;aACV,WAAW,EAAE,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAqB;IAChD,OAAO,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;AAC5C,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAqB;IACpD,IAAI,CAAC;QACH,OAAO,MAAM,GAAG,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,73 @@
1
+ // SWIPIUM Mobile QA Toolkit — profile + check definitions (SWIPIUM-REQ-07 "Mobile QA Toolkit").
2
+ //
3
+ // A named, profile-based mobile-release audit. PURE data + selection logic: the qa_mobile_audit tool
4
+ // turns a chosen profile into an ordered checklist (with expected behavior + report classification)
5
+ // and a safety contract the agent executes via the existing driver tools (qa_act / qa_snapshot /
6
+ // qa_app_control / qa_network …). Keeping the catalog pure makes profile behavior unit-testable.
7
+ export const ALL_PROFILES = ['smoke', 'account_cycle', 'store_compliance', 'resilience', 'release_gate'];
8
+ const CHECKS = {
9
+ launch: { id: 'launch', title: 'App launch + main screen', expected: 'App launches and renders its main screen with no crash/RedBox.', classification: 'blocker_app_bug' },
10
+ health_scan: { id: 'health_scan', title: 'Crash / RedBox / log scan', expected: 'No native crash, RedBox, unhandled exception, or error surface on the main flow.', classification: 'app_bug' },
11
+ navigation: { id: 'navigation', title: 'Basic navigation', expected: 'Primary tabs / navigation are reachable and stable.', classification: 'app_bug' },
12
+ privacy_link: { id: 'privacy_link', title: 'Privacy Policy link', expected: 'Privacy Policy link exists, opens, and is reachable.', classification: 'store_compliance' },
13
+ terms_link: { id: 'terms_link', title: 'Terms link', expected: 'Terms link exists where account/payment/subscription surfaces need it.', classification: 'store_compliance' },
14
+ account_deletion: { id: 'account_deletion', title: 'Account deletion path', expected: 'Account/settings exposes a delete-account or data-deletion flow when the app has accounts.', classification: 'store_compliance' },
15
+ subscription_management: { id: 'subscription_management', title: 'Subscription management / restore', expected: 'Paywall/account exposes restore-purchase and a manage-subscription path or clear system handoff.', classification: 'store_compliance' },
16
+ paywall: { id: 'paywall', title: 'Paywall classification', expected: 'Soft paywall can be dismissed or a free path exists; a hard paywall is recorded without purchase.', classification: 'hard_gate' },
17
+ external_links: { id: 'external_links', title: 'External links', expected: 'External links (support/help/store) open without crashing the app.', classification: 'improvement' },
18
+ create_account: { id: 'create_account', title: 'Create account', expected: 'A safe generated account can be created in test/staging.', classification: 'app_bug', requiresAccountCycle: true, requiresGeneratedData: true },
19
+ logout: { id: 'logout', title: 'Logout', expected: 'User can log out from the disposable test account.', classification: 'app_bug', requiresAccountCycle: true },
20
+ login_again: { id: 'login_again', title: 'Login again', expected: 'The same generated account can log back in.', classification: 'app_bug', requiresAccountCycle: true, requiresGeneratedData: true },
21
+ forgot_password: { id: 'forgot_password', title: 'Forgot password surface', expected: 'A forgot-password entrypoint exists and accepts a test email without consuming email/OTP.', classification: 'improvement', requiresAccountCycle: true },
22
+ offline_entry: { id: 'offline_entry', title: 'Offline entry', expected: 'App handles offline state gracefully (expected offline message, no crash/blank).', classification: 'app_bug' },
23
+ network_restoration: { id: 'network_restoration', title: 'Network restoration', expected: 'App recovers after connectivity returns.', classification: 'app_bug' },
24
+ process_relaunch: { id: 'process_relaunch', title: 'Process kill / relaunch', expected: 'After process kill + relaunch the app restores or returns to a sane state.', classification: 'app_bug' },
25
+ rotation: { id: 'rotation', title: 'Rotation', expected: 'Rotation (where supported) does not crash or lose critical state.', classification: 'improvement' },
26
+ locator_readiness: { id: 'locator_readiness', title: 'Accessibility / test IDs', expected: 'Important buttons/fields have stable locators.', classification: 'accessibility_readiness' },
27
+ issue_recurrence: { id: 'issue_recurrence', title: 'Issue-ledger recurrence', expected: 'No previously-fixed issue has regressed (issue ledger reports no reopened fingerprints).', classification: 'app_bug' },
28
+ };
29
+ const PROFILE_CHECKS = {
30
+ smoke: ['launch', 'health_scan', 'navigation'],
31
+ account_cycle: ['create_account', 'logout', 'login_again', 'forgot_password'],
32
+ store_compliance: ['privacy_link', 'terms_link', 'account_deletion', 'subscription_management', 'paywall', 'external_links'],
33
+ resilience: ['offline_entry', 'network_restoration', 'process_relaunch', 'rotation'],
34
+ release_gate: [], // composed below
35
+ };
36
+ // release_gate combines smoke + account-cycle + store-compliance + resilience + readiness + recurrence.
37
+ PROFILE_CHECKS.release_gate = [
38
+ ...PROFILE_CHECKS.smoke,
39
+ ...PROFILE_CHECKS.account_cycle,
40
+ ...PROFILE_CHECKS.store_compliance,
41
+ ...PROFILE_CHECKS.resilience,
42
+ 'locator_readiness',
43
+ 'issue_recurrence',
44
+ ];
45
+ export function checksForProfile(profile) {
46
+ return PROFILE_CHECKS[profile].map((id) => CHECKS[id]);
47
+ }
48
+ /**
49
+ * Resolve the account-cycle safety contract for a profile. Logout is permitted ONLY in the
50
+ * controlled account-cycle / release-gate profiles, never in broad exploration (spec §Account-cycle
51
+ * safety). A real account is never deleted; OTP/MFA always returns needs_input.
52
+ */
53
+ export function accountCycleSafety(profile, opts = {}) {
54
+ const controlled = profile === 'account_cycle' || profile === 'release_gate';
55
+ const reasons = [];
56
+ if (controlled)
57
+ reasons.push('account-cycle profile: logout permitted as an expected step on a disposable account');
58
+ else
59
+ reasons.push('logout stays destructive outside the controlled account-cycle workflow');
60
+ if (controlled && !opts.allowGeneratedData)
61
+ reasons.push('generated-data permission required: pass allowGeneratedData in test/staging');
62
+ if (opts.allowTestAccountDeletion)
63
+ reasons.push('test-account deletion allowed by explicit policy (disposable accounts only)');
64
+ return {
65
+ allowsLogout: controlled,
66
+ requiresGeneratedData: controlled,
67
+ allowsAccountDeletion: controlled && opts.allowTestAccountDeletion === true,
68
+ neverDeletesRealAccount: true,
69
+ otpReturnsNeedsInput: true,
70
+ reasons,
71
+ };
72
+ }
73
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/mobileAudit/profiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ // SWIPIUM-REQ-08 — executable mobile-audit result model + release-impact rollup.
2
+ import { combineReleaseImpact, defaultReleaseImpact } from '../issues/schema.js';
3
+ /**
4
+ * Release impact of a finished audit run. A failed check with a real-defect / store-compliance /
5
+ * hard-gate category contributes its category's default impact; recurrence of a previously-fixed
6
+ * blocker/high issue blocks. Passing / not-applicable / skipped checks do not raise impact.
7
+ */
8
+ export function auditReleaseImpact(checks, hasBlockingRecurrence) {
9
+ const impacts = [];
10
+ for (const c of checks) {
11
+ if (c.status !== 'fail' && c.status !== 'blocked')
12
+ continue;
13
+ if (!c.category) {
14
+ // a blocked check with no category is at most a warning (environment / setup gap).
15
+ impacts.push('warn');
16
+ continue;
17
+ }
18
+ impacts.push(defaultReleaseImpact(c.category, c.severity ?? 'medium'));
19
+ }
20
+ if (hasBlockingRecurrence)
21
+ impacts.push('block');
22
+ return combineReleaseImpact(impacts);
23
+ }
24
+ /** Map a finished check to a one-line markdown row. */
25
+ export function checkLine(c) {
26
+ const tag = c.issueId ? ` [${c.issueId}]` : '';
27
+ return `- ${c.status.toUpperCase()} — ${c.title}${c.reason ? `: ${c.reason}` : ''}${tag}`;
28
+ }
29
+ /** Render the audit run as a compact markdown block for the report / tool output. */
30
+ export function auditRunToMarkdown(run) {
31
+ const lines = [`## Mobile Audit — ${run.profile}`, '', `State: **${run.state}** · Release impact: **${run.releaseImpact.toUpperCase()}**`, ''];
32
+ for (const c of run.checks)
33
+ lines.push(checkLine(c));
34
+ if (run.recurrenceWarnings.length) {
35
+ lines.push('', '### Recurrence');
36
+ for (const w of run.recurrenceWarnings)
37
+ lines.push(`- ${w}`);
38
+ }
39
+ return lines.join('\n');
40
+ }
41
+ //# sourceMappingURL=results.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results.js","sourceRoot":"","sources":["../../src/mobileAudit/results.ts"],"names":[],"mappings":"AAAA,iFAAiF;AAEjF,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAA8D,MAAM,qBAAqB,CAAC;AAkC7I;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAgC,EAAE,qBAA8B;IACjG,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;YAAE,SAAS;QAC5D,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChB,mFAAmF;YACnF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrB,SAAS;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,qBAAqB;QAAE,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO,oBAAoB,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,SAAS,CAAC,CAAyB;IACjD,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC;AAC5F,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CAAC,GAAyB;IAC1D,MAAM,KAAK,GAAG,CAAC,qBAAqB,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,YAAY,GAAG,CAAC,KAAK,0BAA0B,GAAG,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC/I,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,IAAI,GAAG,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;QACjC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,kBAAkB;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}