@deeeed/metamask-harness 0.38.0 → 0.39.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 (49) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/adapters.js +20 -11
  3. package/library/actions/extension/assets/open_details.mjs +30 -0
  4. package/library/actions/extension/assets/set_token_visibility.mjs +5 -0
  5. package/library/actions/extension/perps/open_balance_action.mjs +1 -6
  6. package/library/actions/extension/perps/search_markets.mjs +32 -0
  7. package/library/actions/extension/perps/select_market_filter.mjs +3 -2
  8. package/library/actions/extension/perps/set_market_favorite.mjs +6 -1
  9. package/library/actions/extension/swap_bridge/read_visible_state.mjs +2 -6
  10. package/library/actions/extension/swap_bridge/set_amount.mjs +11 -2
  11. package/library/actions/extension/swap_bridge/submit_transaction.mjs +11 -11
  12. package/library/actions/mobile/assets/import_custom_token.mjs +181 -0
  13. package/library/actions/mobile/assets/open_details.mjs +43 -0
  14. package/library/actions/mobile/assets/read_details.mjs +96 -0
  15. package/library/actions/mobile/assets/set_token_visibility.mjs +302 -0
  16. package/library/actions/mobile/assets/verify_sorting.mjs +104 -0
  17. package/library/actions/mobile/networks/add_custom.mjs +125 -0
  18. package/library/actions/mobile/networks/network-management.mjs +132 -0
  19. package/library/actions/mobile/networks/read_visible_state.mjs +43 -0
  20. package/library/actions/mobile/networks/remove_custom.mjs +100 -0
  21. package/library/actions/mobile/perps/search_markets.mjs +46 -0
  22. package/library/actions/mobile/perps/set_market_favorite.mjs +117 -0
  23. package/library/actions/mobile/platform/native-session-name.mjs +14 -0
  24. package/library/actions/mobile/platform/native-session.mjs +59 -0
  25. package/library/actions/mobile/platform/observe-ui.mjs +9 -1
  26. package/library/actions/mobile/swap_bridge/native-session.mjs +10 -45
  27. package/library/actions/mobile/swap_bridge/select_assets.mjs +15 -1
  28. package/library/actions/mobile/swap_bridge/set_amount.mjs +1 -1
  29. package/library/actions/mobile/swap_bridge/set_max_amount.mjs +55 -0
  30. package/library/actions/mobile/swap_bridge/set_slippage.mjs +96 -0
  31. package/library/actions/mobile/swap_bridge/submit_transaction.mjs +141 -0
  32. package/library/actions/mobile/ui/native-navigation.mjs +75 -23
  33. package/library/actions/mobile/ui/navigate.mjs +13 -2
  34. package/library/actions/mobile/wallet/lock.mjs +14 -0
  35. package/library/actions/mobile/wallet/native-ui.mjs +67 -14
  36. package/library/actions/shared/perps/visible-state.mjs +8 -6
  37. package/library/actions/shared/swap-bridge/visible-state.mjs +15 -0
  38. package/library/manifests/extension.action-manifest.json +43 -2
  39. package/library/manifests/mobile.action-manifest.json +308 -1
  40. package/library/recipes/assets/release-token-details.recipe.json +5 -4
  41. package/library/recipes/assets/release-token-hide-readd.recipe.json +2 -0
  42. package/library/recipes/mobile/networks/release-custom-network-persistence.recipe.json +90 -0
  43. package/library/recipes/mobile/networks/release-multichain-visibility.recipe.json +58 -0
  44. package/library/recipes/perps/release-market-search.recipe.json +8 -4
  45. package/library/recipes/perps/release-watchlist.recipe.json +31 -19
  46. package/library/recipes/swap-bridge/release-custom-slippage.recipe.json +5 -13
  47. package/package.json +1 -1
  48. package/scripts/validate-release-report.mjs +28 -14
  49. /package/library/recipes/{assets → extension/assets}/release-custom-network-token-persistence.recipe.json +0 -0
@@ -7,14 +7,14 @@
7
7
  "additionalProperties": false,
8
8
  "properties": {
9
9
  "source_symbol": { "type": "string", "default": "ETH" },
10
- "destination_symbol": { "type": "string", "default": "WETH" },
11
- "source_chain": { "type": "string", "default": "eip155:1" },
12
- "destination_chain": { "type": "string", "default": "eip155:1" },
10
+ "destination_symbol": { "type": "string", "default": "USDC" },
11
+ "source_chain": { "type": "string", "default": "eip155:42161" },
12
+ "destination_chain": { "type": "string", "default": "eip155:42161" },
13
13
  "source_query": { "type": "string", "default": "ETH" },
14
- "destination_query": { "type": "string", "default": "WETH" },
14
+ "destination_query": { "type": "string", "default": "USDC" },
15
15
  "source_asset_id": { "type": "string", "default": "" },
16
16
  "destination_asset_id": { "type": "string", "default": "" },
17
- "amount": { "type": "number", "minimum": 0.00000001, "default": 0.0001 },
17
+ "amount": { "type": "number", "minimum": 0.00000001, "default": 0.002 },
18
18
  "slippage": { "type": "number", "minimum": 0.01, "default": 3 },
19
19
  "timeout_ms": { "type": "integer", "minimum": 1000, "default": 60000 }
20
20
  }
@@ -67,14 +67,6 @@
67
67
  "require_quote": true,
68
68
  "expected_slippage": "{{params.slippage}}",
69
69
  "intent": "Prove the live quote retains the custom slippage value",
70
- "next": "wait-for-quote-display"
71
- },
72
- "wait-for-quote-display": {
73
- "action": "ui.wait_for",
74
- "test_id": "minimum-received",
75
- "expected": "visible",
76
- "timeout_ms": "{{params.timeout_ms}}",
77
- "intent": "Confirm the refreshed quote is visible",
78
70
  "next": "capture-quote"
79
71
  },
80
72
  "capture-quote": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.38.0",
3
+ "version": "0.39.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"
@@ -106,23 +106,20 @@ for (const entry of verdictCases) {
106
106
  ];
107
107
  for (const required of requiredDocuments) {
108
108
  const requiredPath = path.join(resolved, required);
109
- if (!fs.existsSync(requiredPath)) {
109
+ const requiredDocument = readRegularJsonFile(requiredPath);
110
+ if (requiredDocument.status === 'missing') {
110
111
  errors.push(`${entry.id ?? '<missing-id>'} evidence directory is missing ${required}: ${resolved}`);
111
112
  continue;
112
113
  }
113
- const requiredStat = fs.lstatSync(requiredPath);
114
- if (requiredStat.isSymbolicLink() || !requiredStat.isFile()) {
114
+ if (requiredDocument.status === 'unsafe') {
115
115
  errors.push(`${entry.id ?? '<missing-id>'} evidence directory ${required} must be a regular file: ${resolved}`);
116
116
  continue;
117
117
  }
118
- let document;
119
- try {
120
- document = JSON.parse(fs.readFileSync(requiredPath, 'utf8'));
121
- } catch {
118
+ if (requiredDocument.status === 'invalid') {
122
119
  errors.push(`${entry.id ?? '<missing-id>'} evidence directory ${required} must contain valid JSON: ${resolved}`);
123
120
  continue;
124
121
  }
125
- documents[required] = document;
122
+ documents[required] = requiredDocument.value;
126
123
  }
127
124
  if (documents['summary.json'] && entry.status === 'PASS' && documents['summary.json'].status !== 'pass') {
128
125
  errors.push(`${entry.id ?? '<missing-id>'} PASS evidence summary.json must have status pass: ${resolved}`);
@@ -216,6 +213,24 @@ function readJson(file, label) {
216
213
  }
217
214
  }
218
215
 
216
+ function readRegularJsonFile(file) {
217
+ let descriptor;
218
+ try {
219
+ descriptor = fs.openSync(file, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
220
+ if (!fs.fstatSync(descriptor).isFile()) return { status: 'unsafe' };
221
+ const contents = fs.readFileSync(descriptor, 'utf8');
222
+ try {
223
+ return { status: 'ok', value: JSON.parse(contents) };
224
+ } catch {
225
+ return { status: 'invalid' };
226
+ }
227
+ } catch (error) {
228
+ return { status: error?.code === 'ENOENT' ? 'missing' : 'unsafe' };
229
+ } finally {
230
+ if (descriptor !== undefined) fs.closeSync(descriptor);
231
+ }
232
+ }
233
+
219
234
  function duplicates(values) {
220
235
  const seen = new Set();
221
236
  const repeated = new Set();
@@ -259,11 +274,10 @@ function readResolvedRecipes(root, resolution, caseId, validationErrors) {
259
274
  if (!fs.existsSync(artifactPath)) continue;
260
275
  const canonicalArtifact = fs.realpathSync(artifactPath);
261
276
  if (!canonicalArtifact.startsWith(`${canonicalRoot}${path.sep}`)) continue;
262
- const stat = fs.lstatSync(artifactPath);
263
- if (stat.isSymbolicLink() || !stat.isFile()) continue;
264
- try {
265
- recipes[digest] = JSON.parse(fs.readFileSync(artifactPath, 'utf8'));
266
- } catch {
277
+ const recipe = readRegularJsonFile(artifactPath);
278
+ if (recipe.status === 'ok') {
279
+ recipes[digest] = recipe.value;
280
+ } else if (recipe.status === 'invalid') {
267
281
  validationErrors.push(`${caseId} evidence directory resolved recipe must contain valid JSON: ${artifactPath}`);
268
282
  }
269
283
  }
@@ -294,7 +308,7 @@ function renderMarkdown(verdicts, inventoryCases, counts, releaseStatus) {
294
308
  }
295
309
 
296
310
  function escapeTable(value) {
297
- return String(value).replace(/\|/gu, '\\|').replace(/\s+/gu, ' ').trim();
311
+ return String(value).replace(/\\/gu, '\\\\').replace(/\|/gu, '\\|').replace(/\s+/gu, ' ').trim();
298
312
  }
299
313
 
300
314
  function parseArgs(argv) {