@mnemonik/cli 7.104.1 → 7.104.4

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 (70) hide show
  1. package/dist/auth/credentials.js +11 -6
  2. package/dist/bin.js +5 -4
  3. package/dist/bin.js.map +1 -1
  4. package/dist/diagnostics.js +11 -6
  5. package/dist/digests.json +68 -64
  6. package/dist/humanReason.d.ts +19 -0
  7. package/dist/humanReason.d.ts.map +1 -0
  8. package/dist/humanReason.js +220 -0
  9. package/dist/humanReason.js.map +1 -0
  10. package/dist/identity/migrate.js +8 -2
  11. package/dist/install/journal.js +8 -2
  12. package/dist/install/journey.d.ts.map +1 -1
  13. package/dist/install/journey.js +48 -23
  14. package/dist/install/journey.js.map +1 -1
  15. package/dist/install/ownership.js +8 -2
  16. package/dist/install/ui.d.ts.map +1 -1
  17. package/dist/install/ui.js +3 -2
  18. package/dist/install/ui.js.map +1 -1
  19. package/dist/installSession.d.ts.map +1 -1
  20. package/dist/installSession.js +3 -2
  21. package/dist/installSession.js.map +1 -1
  22. package/dist/installation.js +8 -2
  23. package/dist/launcher.js +8 -2
  24. package/dist/output.d.ts +1 -1
  25. package/dist/output.d.ts.map +1 -1
  26. package/dist/output.js +4 -2
  27. package/dist/output.js.map +1 -1
  28. package/dist/preflight.d.ts +1 -0
  29. package/dist/preflight.d.ts.map +1 -1
  30. package/dist/preflight.js +23 -22
  31. package/dist/preflight.js.map +1 -1
  32. package/dist/project/records.js +8 -2
  33. package/dist/project.d.ts +2 -0
  34. package/dist/project.d.ts.map +1 -1
  35. package/dist/project.js +41 -28
  36. package/dist/project.js.map +1 -1
  37. package/dist/router.d.ts.map +1 -1
  38. package/dist/router.js +36 -39
  39. package/dist/router.js.map +1 -1
  40. package/dist/runtime/bootstrap.d.ts.map +1 -1
  41. package/dist/runtime/bootstrap.js +57 -9
  42. package/dist/runtime/bootstrap.js.map +1 -1
  43. package/dist/runtime/selfUpdate.d.ts.map +1 -1
  44. package/dist/runtime/selfUpdate.js +10 -3
  45. package/dist/runtime/selfUpdate.js.map +1 -1
  46. package/dist/runtime/signers.js +67 -39
  47. package/dist/runtime/store.js +40 -12
  48. package/dist/runtime/store.js.map +1 -1
  49. package/dist/sbom.json +21 -21
  50. package/dist/scanner/control.js +8 -2
  51. package/dist/scanner/discover.d.ts.map +1 -1
  52. package/dist/scanner/discover.js +17 -17
  53. package/dist/scanner/discover.js.map +1 -1
  54. package/dist/scanner/enable.js +10 -4
  55. package/dist/scanner/enable.js.map +1 -1
  56. package/dist/scanner/picker.d.ts.map +1 -1
  57. package/dist/scanner/picker.js +2 -6
  58. package/dist/scanner/picker.js.map +1 -1
  59. package/dist/scanner/update.js +8 -2
  60. package/dist/scanner-release.json +25 -25
  61. package/dist/screens/journey.d.ts.map +1 -1
  62. package/dist/screens/journey.js +0 -1
  63. package/dist/screens/journey.js.map +1 -1
  64. package/dist/status.d.ts +1 -4
  65. package/dist/status.d.ts.map +1 -1
  66. package/dist/status.js +2 -138
  67. package/dist/status.js.map +1 -1
  68. package/dist/vendor/local-setup.js +19 -5
  69. package/dist/vendor/shared/runtimeSigners.js +65 -19
  70. package/package.json +31 -31
@@ -4,6 +4,7 @@ import { basename, dirname, join, resolve, sep, win32 } from 'node:path';
4
4
  import { createHash, createPublicKey, randomUUID, timingSafeEqual, verify as verifySignature, } from 'node:crypto';
5
5
  import { execFile, execFileSync } from 'node:child_process';
6
6
  import { promisify } from 'node:util';
7
+ import { hostname } from 'node:os';
7
8
  export const execute = (file, args, input) => {
8
9
  const result = promisify(execFile)(file, args);
9
10
  if (input === undefined)
@@ -140,11 +141,12 @@ export async function verifyWindowsAcl(path, run = hookExecute, state) {
140
141
  if (!privateEntries((await drive(saveAcl(path, false, [path], state), run)).get(path), user, false))
141
142
  throw new Error('acl_permissions');
142
143
  }
143
- const aclArgs = (path, sid) => [
144
+ const aclArgs = (path, sid, created = false) => [
144
145
  path,
145
146
  '/inheritance:r',
146
147
  '/grant:r',
147
148
  `*${sid}:(OI)(CI)F`,
149
+ ...(created ? ['/remove:g', '*S-1-5-32-544', '*S-1-5-18'] : []),
148
150
  ];
149
151
  // Keep injected runners at the logical-command boundary; native execution owns encoding.
150
152
  function hookInvocation(file, args) {
@@ -223,7 +225,10 @@ function privateEntries(entries, user, directory) {
223
225
  const ace = /^\(([AD]);((?:OI|CI|NP|IO|ID|SA|FA)*);[A-Za-z0-9]+;;;((?:S-1-(?:\d+-)+\d+)|[A-Z]{2})\)$/.exec(line);
224
226
  if (!ace)
225
227
  throw new Error('acl_unavailable');
226
- return (!directory || !ace[2]?.includes('ID')) && (ace[1] === 'D' || ace[3] === user.sid);
228
+ const ownAlias = ace[3] === 'LA' &&
229
+ user.sid.endsWith('-500') &&
230
+ user.name.toLowerCase().startsWith(hostname().toLowerCase() + '\\');
231
+ return ((!directory || !ace[2]?.includes('ID')) && (ace[1] === 'D' || ace[3] === user.sid || ownAlias));
227
232
  });
228
233
  }
229
234
  const auditDirectories = new Set();
@@ -249,7 +254,7 @@ function* prepareAclDirectory(state) {
249
254
  throw new Error('acl_permissions');
250
255
  if (!auditDirectories.has(directory)) {
251
256
  currentIdentity ??= readIdentity(yield [windowsCommand('whoami.exe'), identityArgs]);
252
- yield [windowsCommand('icacls.exe'), aclArgs(directory, currentIdentity.sid)];
257
+ yield [windowsCommand('icacls.exe'), aclArgs(directory, currentIdentity.sid, created)];
253
258
  if (!created) {
254
259
  const temp = join(directory, `.acl-${randomUUID()}.tmp`);
255
260
  writeFileSync(temp, '', { flag: 'wx', mode: 0o600 });
@@ -319,14 +324,21 @@ function dirEntry(line) {
319
324
  return owner && name ? { owner, name } : undefined;
320
325
  }
321
326
  const unknownOwner = (owner, user) => user.name.length >= ownerWidth || owner.length >= ownerWidth || owner.includes('...');
322
- function ownerLookup(paths) {
327
+ function ownerLookup(paths, restoreOwner) {
323
328
  if (paths.some((path) => /[\t\r\n]/.test(path)))
324
329
  throw new Error('acl_path_unavailable');
325
330
  const script = `$ErrorActionPreference = 'Stop'
326
331
  [Console]::InputEncoding = [System.Text.UTF8Encoding]::new($false)
327
332
  [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
328
333
  while ($null -ne ($path = [Console]::ReadLine())) {
329
- $owner = (Get-Acl -LiteralPath $path).GetOwner([System.Security.Principal.SecurityIdentifier]).Value
334
+ ${restoreOwner
335
+ ? `$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
336
+ if ($identity.User.Value -eq ${quote(restoreOwner)} -and $identity.Owner.Value -eq 'S-1-5-32-544') {
337
+ & ${quote(windowsCommand('icacls.exe'))} $path /setowner ${quote('*' + restoreOwner)} /l | Out-Null
338
+ if ($LASTEXITCODE -ne 0) { throw 'acl_owner' }
339
+ }`
340
+ : ''}
341
+ $owner = [System.IO.File]::GetAccessControl($path).GetOwner([System.Security.Principal.SecurityIdentifier]).Value
330
342
  [Console]::WriteLine($path + "\`t" + $owner)
331
343
  }`;
332
344
  return [
@@ -395,16 +407,28 @@ function* hookPermission(path, created, session, directory = true) {
395
407
  return entry?.name.toLowerCase() === basename(path).toLowerCase() ? [entry.owner] : [];
396
408
  });
397
409
  let owner = owners[0];
398
- if (owners.length === 1 && owner && unknownOwner(owner, user))
410
+ const currentOwner = () => [user.name.toLowerCase(), user.sid.toLowerCase()].includes(owner ?? '');
411
+ if (owners.length === 1 &&
412
+ owner &&
413
+ (unknownOwner(owner, user) || (!currentOwner() && !/^s-1-(?:\d+-)+\d+$/.test(owner))))
399
414
  owner = ownerSids(yield ownerLookup([path])).get(path);
400
- if (owners.length !== 1 ||
401
- ![user.name.toLowerCase(), user.sid.toLowerCase()].includes(owner ?? ''))
415
+ const elevatedOwner = owner === 's-1-5-32-544';
416
+ if (owners.length !== 1 || (!currentOwner() && !elevatedOwner))
402
417
  throw new Error('acl_owner');
403
418
  const icacls = windowsCommand('icacls.exe');
404
419
  if (created)
405
- yield [icacls, aclArgs(path, user.sid)];
420
+ yield [icacls, aclArgs(path, user.sid, true)];
406
421
  let valid = privateEntries((yield* saveAcl(path, false)).get(path), user, directory);
407
- if (!valid && !created && directory) {
422
+ if (elevatedOwner) {
423
+ // Existing group-owned paths must already be private. Only a freshly created
424
+ // directory may have its inherited ACL constrained before restoring its owner.
425
+ if (!valid)
426
+ throw new Error('acl_permissions');
427
+ owner = ownerSids(yield ownerLookup([path], user.sid)).get(path);
428
+ if (!currentOwner())
429
+ throw new Error('acl_owner');
430
+ }
431
+ else if (!valid && !created && directory) {
408
432
  yield [icacls, aclArgs(path, user.sid)];
409
433
  valid = privateEntries((yield* saveAcl(path, false)).get(path), user, directory);
410
434
  }
@@ -424,10 +448,6 @@ function* hookPermission(path, created, session, directory = true) {
424
448
  /* A missing receipt costs another audit next process. */
425
449
  }
426
450
  }
427
- export async function windowsCurrentUserDirectoryAcl(path, run = hookExecute) {
428
- currentIdentity ??= readIdentity(stdout(await run(windowsCommand('whoami.exe'), identityArgs)));
429
- await run(windowsCommand('icacls.exe'), aclArgs(path, currentIdentity.sid));
430
- }
431
451
  export async function protectWindowsDirectory(path, created, run = hookExecute, session = path) {
432
452
  await drive(hookPermission(path, created, session), run);
433
453
  }
@@ -493,14 +513,40 @@ export async function auditWindowsPermissions(state, paths, run = hookExecute, r
493
513
  }
494
514
  const verdicts = new Map();
495
515
  const ownerPaths = [...owners.keys()].filter((path) => path === root || path.startsWith(root + sep));
496
- const truncated = new Set(ownerPaths.filter((path) => owners.get(path)?.includes('...')));
497
- if (truncated.size) {
498
- const result = await run(...ownerLookup([...truncated])).catch(() => ({ stdout: '' }));
516
+ const records = await drive(saveAcl(root, recursive, ownerPaths, tempState), run);
517
+ // Elevated Windows tokens create Administrators-owned files even with a private
518
+ // user DACL. Restore the exact-user invariant, including a failed install's
519
+ // directories, only after proving both the owner SID and the existing DACL.
520
+ const candidates = [...records]
521
+ .filter(([path, entries]) => {
522
+ const owner = owners.get(path);
523
+ if (!owner || owner === user.name.toLowerCase() || owner === user.sid.toLowerCase())
524
+ return false;
525
+ try {
526
+ return privateEntries(entries, user, false);
527
+ }
528
+ catch {
529
+ return false;
530
+ }
531
+ })
532
+ .map(([path]) => path);
533
+ const lookup = new Set([
534
+ ...ownerPaths.filter((path) => owners.get(path)?.includes('...')),
535
+ ...candidates,
536
+ ]);
537
+ if (lookup.size) {
538
+ const result = await run(...ownerLookup([...lookup])).catch(() => ({ stdout: '' }));
499
539
  for (const [path, sid] of ownerSids(stdout(result)))
500
- if (truncated.has(path))
540
+ if (lookup.has(path))
501
541
  owners.set(path, sid);
542
+ const elevated = candidates.filter((path) => owners.get(path) === 's-1-5-32-544');
543
+ if (elevated.length) {
544
+ const restored = ownerSids(stdout(await run(...ownerLookup(elevated, user.sid))));
545
+ for (const path of elevated)
546
+ owners.set(path, restored.get(path) ?? '...');
547
+ }
502
548
  }
503
- for (const [path, entries] of await drive(saveAcl(root, recursive, ownerPaths, tempState), run)) {
549
+ for (const [path, entries] of records) {
504
550
  const owner = owners.get(path) ?? '...';
505
551
  const owned = owner === user.name.toLowerCase() || owner === user.sid.toLowerCase();
506
552
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemonik/cli",
3
- "version": "7.104.1",
3
+ "version": "7.104.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/JayDeeCo-Limited/mnemonik-cli.git"
@@ -34,27 +34,27 @@
34
34
  "hosts": {
35
35
  "claude-code": {
36
36
  "package": "@mnemonik/claude-code-hooks",
37
- "version": "0.9.211",
37
+ "version": "0.9.214",
38
38
  "closure": [
39
39
  {
40
40
  "name": "@mnemonik/claude-code-hooks",
41
- "version": "0.9.211",
42
- "integrity": "sha512-BmuXrQdkn/SBToENe/ZUq0ppb9Sjs0txc+QLHyKN4GAdw1YUWQBPgPTFdn2hmmAtgsc6PUKAo7gnWzjecYKL+g=="
41
+ "version": "0.9.214",
42
+ "integrity": "sha512-85PiXD51d79WbF61NE+QgFB2kjgR1HYxZjAANUmAYRLTh2PVTmtje+OpVsDC47WJsjdcTZl+EO7SrKq8qDZUqw=="
43
43
  },
44
44
  {
45
45
  "name": "@mnemonik/credentials",
46
- "version": "0.1.32",
47
- "integrity": "sha512-h0mACABOgOvqfvH/Ix0pM0z3J5J43yLySgFV7irMqEwI6EpaqcKmTvZQImsS0EwzL5vizzTW/CsqJ+Ke/YIiTA=="
46
+ "version": "0.1.35",
47
+ "integrity": "sha512-XiwRlIABOKrEnOAO+MnBWZQjXPbsi0uC4Qm3Dlge7hsA1Uh69e+1S7KIwp38lv+3nIVUmPXo26ja8xp8oemmcw=="
48
48
  },
49
49
  {
50
50
  "name": "@mnemonik/local-setup",
51
- "version": "0.1.32",
52
- "integrity": "sha512-vkeXDt+wRQ41+lb1LyvZVRGOCd+22CU6rbQIRm58XKh3GSGKp6X/uDn7tJeeqzOQ171uuP2ONACzZ61GVWqqfw=="
51
+ "version": "0.1.35",
52
+ "integrity": "sha512-Tddt66qAvGF7xxTrXQwY7Jyc13rJcLbpYJtyy49PEvWBGPD5k7+nbs2/SDcvMvakPDfLIUdVCoRWfgK6pIYoBQ=="
53
53
  },
54
54
  {
55
55
  "name": "@mnemonik/shared",
56
- "version": "7.104.1",
57
- "integrity": "sha512-iSJQAEF9W+d2aw6M0DAWF9xixKS0Nt5c2oLjxsr6M2Mhr6kdySt4/xua327QbCo5oRHVJhtrBHFU94Fz0r8rvg=="
56
+ "version": "7.104.4",
57
+ "integrity": "sha512-PakAp+aTma4MX8hwCs+Jkg1QiEuSKQPiEG6Cc16mkqOW4kYbS07JCZ93E69doUGrR4xBpbDw1l6iMTMUCaY6TQ=="
58
58
  },
59
59
  {
60
60
  "name": "ignore",
@@ -87,31 +87,31 @@
87
87
  "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
88
88
  }
89
89
  ],
90
- "releaseVersion": "7.104.1"
90
+ "releaseVersion": "7.104.4"
91
91
  },
92
92
  "codex": {
93
93
  "package": "@mnemonik/codex-hooks",
94
- "version": "0.8.180",
94
+ "version": "0.8.183",
95
95
  "closure": [
96
96
  {
97
97
  "name": "@mnemonik/codex-hooks",
98
- "version": "0.8.180",
99
- "integrity": "sha512-ZI9Ceil3RIPtOmtsWHYoJKJSO63cqtcS3ORdZhAo+ABPVLLvswhkv26uSlCMmKWDPV1Jf/f7MzjXCtPWumfHhQ=="
98
+ "version": "0.8.183",
99
+ "integrity": "sha512-QXpQC7gW0sQ0WVgyxMXv87kztFPN26iAcNgGPPF3bsIsV264BGEwvRqPZ8UvctnA41nU56tXFs5vZ/lrFb40lA=="
100
100
  },
101
101
  {
102
102
  "name": "@mnemonik/credentials",
103
- "version": "0.1.32",
104
- "integrity": "sha512-h0mACABOgOvqfvH/Ix0pM0z3J5J43yLySgFV7irMqEwI6EpaqcKmTvZQImsS0EwzL5vizzTW/CsqJ+Ke/YIiTA=="
103
+ "version": "0.1.35",
104
+ "integrity": "sha512-XiwRlIABOKrEnOAO+MnBWZQjXPbsi0uC4Qm3Dlge7hsA1Uh69e+1S7KIwp38lv+3nIVUmPXo26ja8xp8oemmcw=="
105
105
  },
106
106
  {
107
107
  "name": "@mnemonik/local-setup",
108
- "version": "0.1.32",
109
- "integrity": "sha512-vkeXDt+wRQ41+lb1LyvZVRGOCd+22CU6rbQIRm58XKh3GSGKp6X/uDn7tJeeqzOQ171uuP2ONACzZ61GVWqqfw=="
108
+ "version": "0.1.35",
109
+ "integrity": "sha512-Tddt66qAvGF7xxTrXQwY7Jyc13rJcLbpYJtyy49PEvWBGPD5k7+nbs2/SDcvMvakPDfLIUdVCoRWfgK6pIYoBQ=="
110
110
  },
111
111
  {
112
112
  "name": "@mnemonik/shared",
113
- "version": "7.104.1",
114
- "integrity": "sha512-iSJQAEF9W+d2aw6M0DAWF9xixKS0Nt5c2oLjxsr6M2Mhr6kdySt4/xua327QbCo5oRHVJhtrBHFU94Fz0r8rvg=="
113
+ "version": "7.104.4",
114
+ "integrity": "sha512-PakAp+aTma4MX8hwCs+Jkg1QiEuSKQPiEG6Cc16mkqOW4kYbS07JCZ93E69doUGrR4xBpbDw1l6iMTMUCaY6TQ=="
115
115
  },
116
116
  {
117
117
  "name": "ignore",
@@ -144,31 +144,31 @@
144
144
  "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
145
145
  }
146
146
  ],
147
- "releaseVersion": "7.104.1"
147
+ "releaseVersion": "7.104.4"
148
148
  },
149
149
  "cursor": {
150
150
  "package": "@mnemonik/cursor-hooks",
151
- "version": "0.7.167",
151
+ "version": "0.7.170",
152
152
  "closure": [
153
153
  {
154
154
  "name": "@mnemonik/cursor-hooks",
155
- "version": "0.7.167",
156
- "integrity": "sha512-/emJXT6h5S0OLnnnXtCFvLRJbq5bI79BP/E5O9H1JgMsHGJcbLMgM8yz2Q6Are3b5XoH3yVXmq04icxR5xHlgg=="
155
+ "version": "0.7.170",
156
+ "integrity": "sha512-k6c2nfnkB8aStT/dQP56WaFgVU/r1OeKrMdz+SKB65NpnIhWvpu+iKngLWM9SaLo5OslG6Qcc4ttr8Z/yesTQg=="
157
157
  },
158
158
  {
159
159
  "name": "@mnemonik/credentials",
160
- "version": "0.1.32",
161
- "integrity": "sha512-h0mACABOgOvqfvH/Ix0pM0z3J5J43yLySgFV7irMqEwI6EpaqcKmTvZQImsS0EwzL5vizzTW/CsqJ+Ke/YIiTA=="
160
+ "version": "0.1.35",
161
+ "integrity": "sha512-XiwRlIABOKrEnOAO+MnBWZQjXPbsi0uC4Qm3Dlge7hsA1Uh69e+1S7KIwp38lv+3nIVUmPXo26ja8xp8oemmcw=="
162
162
  },
163
163
  {
164
164
  "name": "@mnemonik/local-setup",
165
- "version": "0.1.32",
166
- "integrity": "sha512-vkeXDt+wRQ41+lb1LyvZVRGOCd+22CU6rbQIRm58XKh3GSGKp6X/uDn7tJeeqzOQ171uuP2ONACzZ61GVWqqfw=="
165
+ "version": "0.1.35",
166
+ "integrity": "sha512-Tddt66qAvGF7xxTrXQwY7Jyc13rJcLbpYJtyy49PEvWBGPD5k7+nbs2/SDcvMvakPDfLIUdVCoRWfgK6pIYoBQ=="
167
167
  },
168
168
  {
169
169
  "name": "@mnemonik/shared",
170
- "version": "7.104.1",
171
- "integrity": "sha512-iSJQAEF9W+d2aw6M0DAWF9xixKS0Nt5c2oLjxsr6M2Mhr6kdySt4/xua327QbCo5oRHVJhtrBHFU94Fz0r8rvg=="
170
+ "version": "7.104.4",
171
+ "integrity": "sha512-PakAp+aTma4MX8hwCs+Jkg1QiEuSKQPiEG6Cc16mkqOW4kYbS07JCZ93E69doUGrR4xBpbDw1l6iMTMUCaY6TQ=="
172
172
  },
173
173
  {
174
174
  "name": "ignore",
@@ -201,7 +201,7 @@
201
201
  "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
202
202
  }
203
203
  ],
204
- "releaseVersion": "7.104.1"
204
+ "releaseVersion": "7.104.4"
205
205
  }
206
206
  }
207
207
  }