@mnemonik/cli 7.109.3 → 7.110.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.
- package/dist/auth/credentials.js +297 -36
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1914 -19
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/machineName.d.ts +8 -0
- package/dist/auth/machineName.d.ts.map +1 -0
- package/dist/auth/machineName.js +23 -0
- package/dist/auth/machineName.js.map +1 -0
- package/dist/consent.d.ts +29 -0
- package/dist/consent.d.ts.map +1 -0
- package/dist/consent.js +87 -0
- package/dist/consent.js.map +1 -0
- package/dist/diagnostics.js +301 -40
- package/dist/digests.json +102 -90
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +59 -44
- package/dist/help.js.map +1 -1
- package/dist/humanReason.d.ts +8 -0
- package/dist/humanReason.d.ts.map +1 -1
- package/dist/humanReason.js +44 -16
- package/dist/humanReason.js.map +1 -1
- package/dist/identity/migrate.js +1835 -44
- package/dist/install/hosts.d.ts +2 -0
- package/dist/install/hosts.d.ts.map +1 -1
- package/dist/install/hosts.js +23 -14
- package/dist/install/hosts.js.map +1 -1
- package/dist/install/journal.js +124 -11
- package/dist/install/journey.d.ts +20 -0
- package/dist/install/journey.d.ts.map +1 -1
- package/dist/install/journey.js +1913 -82
- package/dist/install/journey.js.map +1 -1
- package/dist/install/ownership.d.ts.map +1 -1
- package/dist/install/ownership.js +1818 -10
- package/dist/install/ownership.js.map +1 -1
- package/dist/install/transaction.js +1913 -19
- package/dist/install/ui.js +1910 -15
- package/dist/installation.js +133 -10
- package/dist/launcher.js +108 -4
- package/dist/output.d.ts +3 -0
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +11 -1
- package/dist/output.js.map +1 -1
- package/dist/preflight.d.ts +5 -0
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +14 -12
- package/dist/preflight.js.map +1 -1
- package/dist/project/eligibility.js +1917 -22
- package/dist/project/records.js +121 -8
- package/dist/project.d.ts +15 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +229 -15
- package/dist/project.js.map +1 -1
- package/dist/router.d.ts +2 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +2164 -122
- package/dist/router.js.map +1 -1
- package/dist/runtime/releaseSource.d.ts +6 -0
- package/dist/runtime/releaseSource.d.ts.map +1 -1
- package/dist/runtime/releaseSource.js +1933 -32
- package/dist/runtime/releaseSource.js.map +1 -1
- package/dist/runtime/selfUpdate.js +1809 -8
- package/dist/runtime/signers.js +28 -9
- package/dist/runtime/store.js +18 -6
- package/dist/runtime/updateCheck.d.ts +4 -0
- package/dist/runtime/updateCheck.d.ts.map +1 -0
- package/dist/runtime/updateCheck.js +6695 -0
- package/dist/runtime/updateCheck.js.map +1 -0
- package/dist/sbom.json +21 -21
- package/dist/scanner/control.d.ts +27 -1
- package/dist/scanner/control.d.ts.map +1 -1
- package/dist/scanner/control.js +207 -36
- package/dist/scanner/control.js.map +1 -1
- package/dist/scanner/discover.d.ts +5 -0
- package/dist/scanner/discover.d.ts.map +1 -1
- package/dist/scanner/discover.js +16 -6
- package/dist/scanner/discover.js.map +1 -1
- package/dist/scanner/enable.d.ts +2 -0
- package/dist/scanner/enable.d.ts.map +1 -1
- package/dist/scanner/enable.js +152 -14
- package/dist/scanner/enable.js.map +1 -1
- package/dist/scanner/picker.d.ts.map +1 -1
- package/dist/scanner/picker.js +5 -6
- package/dist/scanner/picker.js.map +1 -1
- package/dist/scanner/service.d.ts +2 -0
- package/dist/scanner/service.d.ts.map +1 -1
- package/dist/scanner/service.js +279 -54
- package/dist/scanner/service.js.map +1 -1
- package/dist/scanner/update.d.ts +8 -0
- package/dist/scanner/update.d.ts.map +1 -1
- package/dist/scanner/update.js +254 -20
- package/dist/scanner/update.js.map +1 -1
- package/dist/scanner-release.json +35 -30
- package/dist/screens/journey.d.ts +6 -1
- package/dist/screens/journey.d.ts.map +1 -1
- package/dist/screens/journey.js +29 -8
- package/dist/screens/journey.js.map +1 -1
- package/dist/status.d.ts +21 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +1993 -39
- package/dist/status.js.map +1 -1
- package/dist/vendor/local-setup.js +256 -29
- package/dist/vendor/shared/runtimeSigners.js +38 -11
- package/package.json +31 -31
package/dist/diagnostics.js
CHANGED
|
@@ -502,7 +502,9 @@ var require_ignore = __commonJS({
|
|
|
502
502
|
});
|
|
503
503
|
|
|
504
504
|
// packages/shared/dist/runtimeSigners.js
|
|
505
|
+
import { lstatSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync } from "node:fs";
|
|
505
506
|
import { basename, dirname as dirname2, join as join2, resolve, sep, win32 } from "node:path";
|
|
507
|
+
import { createHash, createPublicKey, randomUUID, timingSafeEqual, verify as verifySignature } from "node:crypto";
|
|
506
508
|
import { execFile, execFileSync } from "node:child_process";
|
|
507
509
|
function windowsCommand(file) {
|
|
508
510
|
const root = process.env.SystemRoot;
|
|
@@ -510,14 +512,44 @@ function windowsCommand(file) {
|
|
|
510
512
|
throw new Error("acl_system_root_unavailable");
|
|
511
513
|
return win32.join(root, "System32", file);
|
|
512
514
|
}
|
|
513
|
-
function readIdentity(
|
|
514
|
-
const match = /^"([^"\r\n]+)","(S-1-(?:\d+-)+\d+)"$/.exec(
|
|
515
|
-
if (!match?.[1] || !match[2] ||
|
|
515
|
+
function readIdentity(stdout2) {
|
|
516
|
+
const match = /^"([^"\r\n]+)","(S-1-(?:\d+-)+\d+)"$/.exec(stdout2.trim());
|
|
517
|
+
if (!match?.[1] || !match[2] || stdout2.includes("\uFFFD"))
|
|
516
518
|
throw new Error("acl_identity_unavailable");
|
|
517
519
|
return { name: match[1], sid: match[2] };
|
|
518
520
|
}
|
|
521
|
+
function* readWindowsIdentity() {
|
|
522
|
+
const user = readIdentity(yield [windowsCommand("whoami.exe"), identityArgs]);
|
|
523
|
+
if (!ADMINISTRATOR_RID.test(user.sid))
|
|
524
|
+
return user;
|
|
525
|
+
const groups = yield [windowsCommand("whoami.exe"), groupArgs];
|
|
526
|
+
const local = /^"[^"\r\n]*","[^"\r\n]*","S-1-5-113",/m.test(groups);
|
|
527
|
+
return {
|
|
528
|
+
...user,
|
|
529
|
+
localAdministratorSid: local ? `${user.sid.slice(0, user.sid.lastIndexOf("-"))}-500` : null
|
|
530
|
+
};
|
|
531
|
+
}
|
|
519
532
|
function windowsCurrentAccountSync() {
|
|
520
|
-
|
|
533
|
+
if (currentIdentity)
|
|
534
|
+
return currentIdentity;
|
|
535
|
+
const commands = readWindowsIdentity();
|
|
536
|
+
let step = commands.next();
|
|
537
|
+
while (!step.done)
|
|
538
|
+
step = commands.next(hookExecuteSync(...step.value));
|
|
539
|
+
return currentIdentity = step.value;
|
|
540
|
+
}
|
|
541
|
+
async function windowsIdentity(run2) {
|
|
542
|
+
if (currentIdentity)
|
|
543
|
+
return currentIdentity;
|
|
544
|
+
identityPending ??= drive(readWindowsIdentity(), run2).then((identity) => currentIdentity = identity).finally(() => {
|
|
545
|
+
identityPending = void 0;
|
|
546
|
+
});
|
|
547
|
+
return identityPending;
|
|
548
|
+
}
|
|
549
|
+
async function verifyWindowsAcl(path, run2 = hookExecute, state) {
|
|
550
|
+
const user = await windowsIdentity(run2);
|
|
551
|
+
if (!privateEntries((await drive(saveAcl(path, false, [path], state), run2)).get(path), user, false))
|
|
552
|
+
throw new Error("acl_permissions");
|
|
521
553
|
}
|
|
522
554
|
function hookInvocation(file, args2) {
|
|
523
555
|
if (win32.basename(file) === "whoami.exe") {
|
|
@@ -537,12 +569,112 @@ function hookExecuteSync(file, args2, input) {
|
|
|
537
569
|
[file, args2] = hookInvocation(file, args2);
|
|
538
570
|
return execFileSync(file, args2, { ...hookOptions(file, args2), input });
|
|
539
571
|
}
|
|
540
|
-
|
|
572
|
+
function aclRecords(output, root, paths, onLookup) {
|
|
573
|
+
const records = /* @__PURE__ */ new Map();
|
|
574
|
+
const wanted = new Set(paths);
|
|
575
|
+
const lines = output.replace(/^\uFEFF/, "").trimEnd().split(/\r?\n/);
|
|
576
|
+
if (lines.length % 2)
|
|
577
|
+
throw new Error("acl_unavailable");
|
|
578
|
+
for (let index = 0; index < lines.length; index += 2) {
|
|
579
|
+
onLookup?.();
|
|
580
|
+
const relativePath = lines[index];
|
|
581
|
+
const descriptor = lines[index + 1];
|
|
582
|
+
if (relativePath === void 0 || descriptor === void 0)
|
|
583
|
+
throw new Error("acl_unavailable");
|
|
584
|
+
const path = resolve(dirname2(root), relativePath.replaceAll("\\", sep));
|
|
585
|
+
if (!wanted.has(path))
|
|
586
|
+
continue;
|
|
587
|
+
if (records.has(path))
|
|
588
|
+
throw new Error("acl_unavailable");
|
|
589
|
+
const dacl = /^D:(?:P|AI|AR)*((?:\([^()]*\))*)$/.exec(descriptor);
|
|
590
|
+
records.set(path, dacl?.[1]?.match(/\([^()]*\)/g) ?? []);
|
|
591
|
+
}
|
|
592
|
+
return records;
|
|
593
|
+
}
|
|
594
|
+
function privateEntries(entries, user, directory) {
|
|
595
|
+
if (!entries?.length)
|
|
596
|
+
throw new Error("acl_unavailable");
|
|
597
|
+
return entries.every((line) => {
|
|
598
|
+
const ace = /^\(([AD]);((?:OI|CI|NP|IO|ID|SA|FA)*);[A-Za-z0-9]+;;;((?:S-1-(?:\d+-)+\d+)|[A-Z]{2})\)$/.exec(line);
|
|
599
|
+
if (!ace)
|
|
600
|
+
throw new Error("acl_unavailable");
|
|
601
|
+
const sid = ace[3] === "LA" ? user.localAdministratorSid : ace[3];
|
|
602
|
+
return (!directory || !ace[2]?.includes("ID")) && (ace[1] === "D" || sid === user.sid);
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
function* prepareAclDirectory(state) {
|
|
606
|
+
const directory = join2(state, "audit-tmp");
|
|
607
|
+
if (auditDirectories.has(directory)) {
|
|
608
|
+
const stat2 = lstatSync(directory);
|
|
609
|
+
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
610
|
+
throw new Error("acl_permissions");
|
|
611
|
+
return directory;
|
|
612
|
+
}
|
|
613
|
+
let created = false;
|
|
614
|
+
try {
|
|
615
|
+
mkdirSync(directory, { mode: 448 });
|
|
616
|
+
created = true;
|
|
617
|
+
} catch (error) {
|
|
618
|
+
if (error.code !== "EEXIST")
|
|
619
|
+
throw error;
|
|
620
|
+
}
|
|
621
|
+
const stat = lstatSync(directory);
|
|
622
|
+
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
623
|
+
throw new Error("acl_permissions");
|
|
624
|
+
if (!auditDirectories.has(directory)) {
|
|
625
|
+
currentIdentity ??= yield* readWindowsIdentity();
|
|
626
|
+
yield [windowsCommand("icacls.exe"), aclArgs(directory, currentIdentity.sid, created)];
|
|
627
|
+
if (!created) {
|
|
628
|
+
const temp = join2(directory, `.acl-${randomUUID()}.tmp`);
|
|
629
|
+
writeFileSync(temp, "", { flag: "wx", mode: 384 });
|
|
630
|
+
try {
|
|
631
|
+
yield [windowsCommand("icacls.exe"), [directory, "/save", temp, "/l"]];
|
|
632
|
+
if (!privateEntries(aclRecords(readFileSync(temp, "utf16le"), directory, [directory]).get(directory), currentIdentity, true))
|
|
633
|
+
throw new Error("acl_permissions");
|
|
634
|
+
} finally {
|
|
635
|
+
unlinkSync(temp);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
auditDirectories.add(directory);
|
|
639
|
+
}
|
|
640
|
+
return directory;
|
|
641
|
+
}
|
|
642
|
+
function* saveAcl(path, recursive, paths = [path], state = lstatSync(path).isDirectory() ? path : dirname2(path)) {
|
|
643
|
+
const directory = yield* prepareAclDirectory(state);
|
|
644
|
+
const temp = join2(directory, `.acl-${randomUUID()}.tmp`);
|
|
645
|
+
writeFileSync(temp, "", { flag: "wx", mode: 384 });
|
|
646
|
+
try {
|
|
647
|
+
yield [windowsCommand("icacls.exe"), [path, "/save", temp, ...recursive ? ["/t"] : [], "/l"]];
|
|
648
|
+
return aclRecords(readFileSync(temp, "utf16le"), path, paths.filter((item) => item !== directory && !item.startsWith(directory + sep)));
|
|
649
|
+
} finally {
|
|
650
|
+
unlinkSync(temp);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
async function drive(commands, run2) {
|
|
654
|
+
try {
|
|
655
|
+
let step = commands.next();
|
|
656
|
+
while (!step.done)
|
|
657
|
+
step = commands.next(stdout(await run2(...step.value)));
|
|
658
|
+
return step.value;
|
|
659
|
+
} finally {
|
|
660
|
+
commands.return(void 0);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
var identityArgs, groupArgs, ADMINISTRATOR_RID, currentIdentity, ttl, identityPending, aclArgs, hookOptions, hookExecute, stdout, auditDirectories;
|
|
541
664
|
var init_runtimeSigners = __esm({
|
|
542
665
|
"packages/shared/dist/runtimeSigners.js"() {
|
|
543
666
|
"use strict";
|
|
544
667
|
identityArgs = ["/user", "/fo", "csv", "/nh"];
|
|
668
|
+
groupArgs = ["/groups", "/fo", "csv", "/nh"];
|
|
669
|
+
ADMINISTRATOR_RID = /^S-1-5-21-\d+-\d+-\d+-500$/;
|
|
545
670
|
ttl = 10 * 6e4;
|
|
671
|
+
aclArgs = (path, sid, created = false) => [
|
|
672
|
+
path,
|
|
673
|
+
"/inheritance:r",
|
|
674
|
+
"/grant:r",
|
|
675
|
+
`*${sid}:(OI)(CI)F`,
|
|
676
|
+
...created ? ["/remove:g", "*S-1-5-32-544", "*S-1-5-18"] : []
|
|
677
|
+
];
|
|
546
678
|
hookOptions = (file, args2) => ({
|
|
547
679
|
encoding: args2.includes("/u") ? "utf16le" : "utf8",
|
|
548
680
|
timeout: win32.basename(file) === "powershell.exe" ? 3e4 : 5e3,
|
|
@@ -550,6 +682,22 @@ var init_runtimeSigners = __esm({
|
|
|
550
682
|
maxBuffer: 16 * 1024 * 1024,
|
|
551
683
|
windowsVerbatimArguments: win32.basename(file) === "cmd.exe"
|
|
552
684
|
});
|
|
685
|
+
hookExecute = (file, args2, input) => {
|
|
686
|
+
const treeListing = win32.basename(file) === "icacls.exe" && args2.includes("/t") || win32.basename(file) === "cmd.exe" && args2.some((arg) => arg.startsWith("dir /q /a /s "));
|
|
687
|
+
[file, args2] = hookInvocation(file, args2);
|
|
688
|
+
const options = hookOptions(file, args2);
|
|
689
|
+
if (treeListing)
|
|
690
|
+
options.timeout = 3e4;
|
|
691
|
+
return new Promise((resolve3, reject) => {
|
|
692
|
+
const child = execFile(file, args2, options, (error, stdout2) => error ? reject(error) : resolve3({ stdout: stdout2 }));
|
|
693
|
+
if (input !== void 0) {
|
|
694
|
+
child.stdin?.on("error", reject);
|
|
695
|
+
child.stdin?.end(input);
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
};
|
|
699
|
+
stdout = (value) => value.stdout;
|
|
700
|
+
auditDirectories = /* @__PURE__ */ new Set();
|
|
553
701
|
}
|
|
554
702
|
});
|
|
555
703
|
|
|
@@ -2197,14 +2345,14 @@ var require_proper_lockfile = __commonJS({
|
|
|
2197
2345
|
});
|
|
2198
2346
|
|
|
2199
2347
|
// packages/cli/src/diagnostics.ts
|
|
2200
|
-
import { createHash as
|
|
2348
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
2201
2349
|
import { execFile as nodeExecFile2 } from "node:child_process";
|
|
2202
2350
|
import { lstat as lstat2, mkdir as mkdir3, readFile as readFile2 } from "node:fs/promises";
|
|
2203
|
-
import { dirname as dirname5, join as
|
|
2351
|
+
import { dirname as dirname5, join as join7 } from "node:path";
|
|
2204
2352
|
|
|
2205
2353
|
// packages/credentials/dist/index.js
|
|
2206
2354
|
import { createHmac, randomBytes } from "node:crypto";
|
|
2207
|
-
import { join as
|
|
2355
|
+
import { join as join6 } from "node:path";
|
|
2208
2356
|
|
|
2209
2357
|
// packages/shared/dist/instructions.js
|
|
2210
2358
|
var INSTRUCTIONS_CONTENT = `Mnemonik provides persistent project memory: decisions, rationale, tasks, and policies across sessions. If no block begins "PROJECT_CONTEXT schemaVersion=", session_bootstrap({ cwd }) loads project context when cwd is the real absolute path of the project root; a placeholder or relative path fails. With that block, context is loaded and no session_bootstrap call is needed. Code and docs show current artifacts, git shows changes, and memory carries the why; memory_search recalls rationale or intent, then Grep or Read verifies current source.
|
|
@@ -6399,7 +6547,7 @@ init_repositoryRoot();
|
|
|
6399
6547
|
// packages/local-setup/dist/storage.js
|
|
6400
6548
|
init_hookRuntime();
|
|
6401
6549
|
init_hookRuntime();
|
|
6402
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
6550
|
+
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
6403
6551
|
import { execFile as nodeExecFile } from "node:child_process";
|
|
6404
6552
|
import fs2 from "node:fs";
|
|
6405
6553
|
import { open, rename, readFile, mkdir, lstat, chmod, writeFile, unlink, rmdir } from "node:fs/promises";
|
|
@@ -6462,6 +6610,9 @@ async function windowsCurrentUserAcl(path, directory = false, options = {}, crea
|
|
|
6462
6610
|
});
|
|
6463
6611
|
});
|
|
6464
6612
|
}
|
|
6613
|
+
async function verifyWindowsCurrentUserOnly(path, state, run2) {
|
|
6614
|
+
await verifyWindowsAcl(path, run2, state);
|
|
6615
|
+
}
|
|
6465
6616
|
async function protectStateFile(path, platform = process.platform, aclOptions) {
|
|
6466
6617
|
if (platform === "win32")
|
|
6467
6618
|
await windowsCurrentUserAcl(path, false, aclOptions);
|
|
@@ -6471,7 +6622,7 @@ async function protectStateFile(path, platform = process.platform, aclOptions) {
|
|
|
6471
6622
|
}
|
|
6472
6623
|
async function atomicWrite(path, bytes, fault, assertOwned) {
|
|
6473
6624
|
await assertOwned?.();
|
|
6474
|
-
const temp = `${path}.${
|
|
6625
|
+
const temp = `${path}.${randomUUID2()}.tmp`;
|
|
6475
6626
|
const fd = await open(temp, "wx", 384);
|
|
6476
6627
|
let permissionStatus;
|
|
6477
6628
|
try {
|
|
@@ -6493,7 +6644,7 @@ async function atomicWrite(path, bytes, fault, assertOwned) {
|
|
|
6493
6644
|
async function withLock(path, waitMs, work) {
|
|
6494
6645
|
const lockfile = await sharedLockfile();
|
|
6495
6646
|
await mkdir(dirname3(path), { recursive: true, mode: 448 });
|
|
6496
|
-
const generation =
|
|
6647
|
+
const generation = randomUUID2();
|
|
6497
6648
|
const owner = join3(`${path}.lock`, "owner");
|
|
6498
6649
|
let compromised = false;
|
|
6499
6650
|
let acquired = false;
|
|
@@ -6558,6 +6709,100 @@ async function withLock(path, waitMs, work) {
|
|
|
6558
6709
|
}
|
|
6559
6710
|
}
|
|
6560
6711
|
|
|
6712
|
+
// packages/local-setup/dist/automaticUpdate.js
|
|
6713
|
+
import { spawn as nodeSpawn } from "node:child_process";
|
|
6714
|
+
import { realpathSync } from "node:fs";
|
|
6715
|
+
import { stat as nodeStat, utimes } from "node:fs/promises";
|
|
6716
|
+
import { homedir as homedir2 } from "node:os";
|
|
6717
|
+
import { join as join4 } from "node:path";
|
|
6718
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
6719
|
+
var DAY_MS = 864e5;
|
|
6720
|
+
var statePath = (stateDir) => join4(stateDir, "automatic-update.json");
|
|
6721
|
+
function cliLauncherPath(options = {}) {
|
|
6722
|
+
const platform = options.platform ?? process.platform;
|
|
6723
|
+
const home = options.home ?? homedir2();
|
|
6724
|
+
return platform === "win32" ? join4(options.env?.LOCALAPPDATA || join4(home, "AppData", "Local"), "Mnemonik", "bin", "mnemonik.cmd") : join4(home, ".local", "bin", "mnemonik");
|
|
6725
|
+
}
|
|
6726
|
+
async function readState(path) {
|
|
6727
|
+
const bytes = await readBytes(path);
|
|
6728
|
+
if (!bytes)
|
|
6729
|
+
return {};
|
|
6730
|
+
const value = JSON.parse(bytes.toString());
|
|
6731
|
+
if (!value || typeof value !== "object" || value.lastAttempt !== void 0 && (!Number.isFinite(value.lastAttempt) || value.lastAttempt < 0))
|
|
6732
|
+
throw new Error("automatic_update_state_invalid");
|
|
6733
|
+
return value.lastAttempt === void 0 ? {} : { lastAttempt: value.lastAttempt };
|
|
6734
|
+
}
|
|
6735
|
+
async function maybeStartAutomaticUpdate(options = {}) {
|
|
6736
|
+
const stateDir = options.stateDir ?? stateDirectory(options.platform, options.env, options.home);
|
|
6737
|
+
const path = statePath(stateDir);
|
|
6738
|
+
try {
|
|
6739
|
+
const now = (options.now ?? Date.now)();
|
|
6740
|
+
const stat = options.stat ?? nodeStat;
|
|
6741
|
+
try {
|
|
6742
|
+
if (now - (await stat(path)).mtimeMs < DAY_MS)
|
|
6743
|
+
return false;
|
|
6744
|
+
} catch (error) {
|
|
6745
|
+
if (error.code !== "ENOENT")
|
|
6746
|
+
throw error;
|
|
6747
|
+
}
|
|
6748
|
+
if (!options.spawn && !(await stat(cliLauncherPath(options))).isFile())
|
|
6749
|
+
return false;
|
|
6750
|
+
return await withLock(path, 0, async (assertOwned) => {
|
|
6751
|
+
const state = await readState(path);
|
|
6752
|
+
if (state.lastAttempt !== void 0 && now - state.lastAttempt < DAY_MS)
|
|
6753
|
+
return false;
|
|
6754
|
+
await atomicWrite(path, Buffer.from(`${JSON.stringify({ lastAttempt: now })}
|
|
6755
|
+
`), void 0, assertOwned);
|
|
6756
|
+
await utimes(path, now / 1e3, now / 1e3);
|
|
6757
|
+
const platform = options.platform ?? process.platform;
|
|
6758
|
+
const launcher = cliLauncherPath(options);
|
|
6759
|
+
const command = platform === "win32" ? {
|
|
6760
|
+
file: options.env?.ComSpec || "cmd.exe",
|
|
6761
|
+
args: ["/d", "/s", "/c", `""${launcher}" update --automatic"`],
|
|
6762
|
+
windowsVerbatimArguments: true
|
|
6763
|
+
} : platform === "linux" && (options.env ?? process.env).INVOCATION_ID ? {
|
|
6764
|
+
// detached creates a process group, not a new systemd cgroup. An
|
|
6765
|
+
// updater spawned by the scanner must survive stopping that service.
|
|
6766
|
+
file: "systemd-run",
|
|
6767
|
+
args: [
|
|
6768
|
+
"--user",
|
|
6769
|
+
"--collect",
|
|
6770
|
+
"--quiet",
|
|
6771
|
+
`--setenv=MNEMONIK_STATE_DIR=${stateDir}`,
|
|
6772
|
+
"--",
|
|
6773
|
+
launcher,
|
|
6774
|
+
"update",
|
|
6775
|
+
"--automatic"
|
|
6776
|
+
]
|
|
6777
|
+
} : { file: launcher, args: ["update", "--automatic"] };
|
|
6778
|
+
const child = (options.spawn ?? nodeSpawn)(command.file, command.args, {
|
|
6779
|
+
detached: true,
|
|
6780
|
+
stdio: "ignore",
|
|
6781
|
+
windowsHide: true,
|
|
6782
|
+
..."windowsVerbatimArguments" in command ? { windowsVerbatimArguments: command.windowsVerbatimArguments } : {}
|
|
6783
|
+
});
|
|
6784
|
+
child.once("error", () => {
|
|
6785
|
+
});
|
|
6786
|
+
child.unref();
|
|
6787
|
+
return true;
|
|
6788
|
+
});
|
|
6789
|
+
} catch {
|
|
6790
|
+
return false;
|
|
6791
|
+
}
|
|
6792
|
+
}
|
|
6793
|
+
var HELPER_FLAG = "--mnemonik-automatic-update";
|
|
6794
|
+
function isHelperInvocation() {
|
|
6795
|
+
if (process.argv[2] !== HELPER_FLAG || !process.argv[3] || !process.argv[1])
|
|
6796
|
+
return false;
|
|
6797
|
+
try {
|
|
6798
|
+
return realpathSync(process.argv[1]) === realpathSync(fileURLToPath2(import.meta.url));
|
|
6799
|
+
} catch {
|
|
6800
|
+
return false;
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
if (isHelperInvocation())
|
|
6804
|
+
void maybeStartAutomaticUpdate({ stateDir: process.argv[3] });
|
|
6805
|
+
|
|
6561
6806
|
// packages/local-setup/dist/index.js
|
|
6562
6807
|
var MAX_ORIGINAL_BYTES = 64 * 1024;
|
|
6563
6808
|
|
|
@@ -6573,10 +6818,10 @@ var CredentialSessionUnavailableError = class extends Error {
|
|
|
6573
6818
|
};
|
|
6574
6819
|
|
|
6575
6820
|
// packages/credentials/dist/storage.js
|
|
6576
|
-
import { createHash as
|
|
6821
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
6577
6822
|
import { lstat as nodeLstat, mkdir as mkdir2, open as open2, readdir, rmdir as rmdir2, unlink as unlink2 } from "node:fs/promises";
|
|
6578
6823
|
import { constants } from "node:fs";
|
|
6579
|
-
import { basename as basename2, dirname as dirname4, isAbsolute, join as
|
|
6824
|
+
import { basename as basename2, dirname as dirname4, isAbsolute, join as join5, parse, relative, resolve as resolve2, sep as sep2 } from "node:path";
|
|
6580
6825
|
var CredentialError = class extends Error {
|
|
6581
6826
|
reason;
|
|
6582
6827
|
constructor(reason) {
|
|
@@ -6585,22 +6830,22 @@ var CredentialError = class extends Error {
|
|
|
6585
6830
|
this.name = "CredentialError";
|
|
6586
6831
|
}
|
|
6587
6832
|
};
|
|
6588
|
-
var digest = (value) =>
|
|
6833
|
+
var digest = (value) => createHash3("sha256").update(value).digest("hex");
|
|
6589
6834
|
function credentialPaths(stateDir = stateDirectory(), familyId) {
|
|
6590
|
-
const root =
|
|
6835
|
+
const root = join5(stateDir, "credentials");
|
|
6591
6836
|
const familyName = familyId ? digest(familyId) : "";
|
|
6592
6837
|
return {
|
|
6593
6838
|
root,
|
|
6594
|
-
records:
|
|
6595
|
-
secrets:
|
|
6596
|
-
cliRecord:
|
|
6597
|
-
cliSecret:
|
|
6598
|
-
rootRecord:
|
|
6599
|
-
rootSecret:
|
|
6600
|
-
familyRecords:
|
|
6601
|
-
familySecrets:
|
|
6602
|
-
record:
|
|
6603
|
-
secret:
|
|
6839
|
+
records: join5(root, "records"),
|
|
6840
|
+
secrets: join5(root, "secrets"),
|
|
6841
|
+
cliRecord: join5(root, "records", "cli.json"),
|
|
6842
|
+
cliSecret: join5(root, "secrets", "cli.json"),
|
|
6843
|
+
rootRecord: join5(root, "records", "root-binding.json"),
|
|
6844
|
+
rootSecret: join5(root, "secrets", "root-binding.key"),
|
|
6845
|
+
familyRecords: join5(root, "records", "families"),
|
|
6846
|
+
familySecrets: join5(root, "secrets", "families"),
|
|
6847
|
+
record: join5(root, "records", "families", `${familyName}.json`),
|
|
6848
|
+
secret: join5(root, "secrets", "families", `${familyName}.json`)
|
|
6604
6849
|
};
|
|
6605
6850
|
}
|
|
6606
6851
|
var codeIs2 = (error, code) => error.code === code;
|
|
@@ -6612,6 +6857,7 @@ var SecureFiles = class {
|
|
|
6612
6857
|
fault;
|
|
6613
6858
|
execFile;
|
|
6614
6859
|
username;
|
|
6860
|
+
aclRun;
|
|
6615
6861
|
constructor(options = {}) {
|
|
6616
6862
|
this.stateDir = resolve2(options.stateDir ?? stateDirectory());
|
|
6617
6863
|
this.platform = options.platform ?? process.platform;
|
|
@@ -6620,6 +6866,7 @@ var SecureFiles = class {
|
|
|
6620
6866
|
this.fault = options.fault;
|
|
6621
6867
|
this.execFile = options.execFile;
|
|
6622
6868
|
this.username = options.username;
|
|
6869
|
+
this.aclRun = options.aclRun;
|
|
6623
6870
|
}
|
|
6624
6871
|
assertInsideState(path) {
|
|
6625
6872
|
const absolute = resolve2(path);
|
|
@@ -6635,7 +6882,7 @@ var SecureFiles = class {
|
|
|
6635
6882
|
const result = [];
|
|
6636
6883
|
let current = root;
|
|
6637
6884
|
for (const part of parts2) {
|
|
6638
|
-
current =
|
|
6885
|
+
current = join5(current, part);
|
|
6639
6886
|
result.push(current);
|
|
6640
6887
|
}
|
|
6641
6888
|
return result;
|
|
@@ -6654,20 +6901,34 @@ var SecureFiles = class {
|
|
|
6654
6901
|
if (value.isSymbolicLink())
|
|
6655
6902
|
throw new CredentialError("symlink_rejected");
|
|
6656
6903
|
const protectedComponent = component === this.stateDir || component.startsWith(`${this.stateDir}${sep2}`);
|
|
6657
|
-
if (!protectedComponent
|
|
6904
|
+
if (!protectedComponent)
|
|
6658
6905
|
continue;
|
|
6659
|
-
if (this.uid !== void 0 && value.uid !== this.uid)
|
|
6660
|
-
throw new CredentialError("wrong_owner");
|
|
6661
6906
|
const final = component === absolute;
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6907
|
+
if (this.platform === "win32") {
|
|
6908
|
+
if (final)
|
|
6909
|
+
await this.verifyWindowsPrivate(component);
|
|
6910
|
+
} else {
|
|
6911
|
+
if (this.uid !== void 0 && value.uid !== this.uid)
|
|
6912
|
+
throw new CredentialError("wrong_owner");
|
|
6913
|
+
const allowed = final && expectFile ? 384 : 448;
|
|
6914
|
+
if ((value.mode & 511 & ~allowed) !== 0)
|
|
6915
|
+
throw new CredentialError("weak_permissions");
|
|
6916
|
+
}
|
|
6665
6917
|
if (final && expectFile && !value.isFile())
|
|
6666
6918
|
throw new CredentialError("not_regular_file");
|
|
6667
6919
|
if (final && !expectFile && !value.isDirectory())
|
|
6668
6920
|
throw new CredentialError("not_regular_file");
|
|
6669
6921
|
}
|
|
6670
6922
|
}
|
|
6923
|
+
async verifyWindowsPrivate(path) {
|
|
6924
|
+
try {
|
|
6925
|
+
await verifyWindowsCurrentUserOnly(path, this.stateDir, this.aclRun);
|
|
6926
|
+
} catch (error) {
|
|
6927
|
+
if (error.message === "acl_permissions")
|
|
6928
|
+
throw new CredentialError("weak_permissions");
|
|
6929
|
+
throw error;
|
|
6930
|
+
}
|
|
6931
|
+
}
|
|
6671
6932
|
async makeDirectory(path) {
|
|
6672
6933
|
let created = false;
|
|
6673
6934
|
try {
|
|
@@ -6721,7 +6982,7 @@ var SecureFiles = class {
|
|
|
6721
6982
|
const prefix = `${basename2(absolute)}.`;
|
|
6722
6983
|
for (const name2 of await this.list(dirname4(absolute))) {
|
|
6723
6984
|
if (name2.startsWith(prefix) && name2.endsWith(".tmp"))
|
|
6724
|
-
await this.remove(
|
|
6985
|
+
await this.remove(join5(dirname4(absolute), name2));
|
|
6725
6986
|
}
|
|
6726
6987
|
throw error;
|
|
6727
6988
|
}
|
|
@@ -7256,7 +7517,7 @@ function createCredentialAdapter(options = {}) {
|
|
|
7256
7517
|
const cli = await readRecord(paths.cliRecord, "cli-oauth");
|
|
7257
7518
|
const componentFamilyIds = [];
|
|
7258
7519
|
for (const name2 of await files.list(paths.familyRecords)) {
|
|
7259
|
-
const recordPath2 =
|
|
7520
|
+
const recordPath2 = join6(paths.familyRecords, name2);
|
|
7260
7521
|
const record = await readRecord(recordPath2, "component");
|
|
7261
7522
|
if (!record)
|
|
7262
7523
|
continue;
|
|
@@ -7313,10 +7574,10 @@ var DiagnosticsError = class extends Error {
|
|
|
7313
7574
|
}
|
|
7314
7575
|
code;
|
|
7315
7576
|
};
|
|
7316
|
-
var digest2 = (bytes) =>
|
|
7577
|
+
var digest2 = (bytes) => createHash4("sha256").update(bytes).digest("hex");
|
|
7317
7578
|
var validId = (id) => /^diag-[A-Za-z0-9._-]{1,120}$/u.test(id);
|
|
7318
7579
|
async function scannerConfig(stateDir) {
|
|
7319
|
-
const state = JSON.parse(await readFile2(
|
|
7580
|
+
const state = JSON.parse(await readFile2(join7(stateDir, "scanner", "state.json"), "utf8"));
|
|
7320
7581
|
if (typeof state.config?.serverUrl !== "string" || typeof state.config.credentialFamilyId !== "string")
|
|
7321
7582
|
throw new DiagnosticsError("scanner_credential_missing");
|
|
7322
7583
|
return {
|
|
@@ -7345,7 +7606,7 @@ async function previewDiagnostics(out2, dependencies = {}) {
|
|
|
7345
7606
|
const stateDir = dependencies.stateDir ?? stateDirectory();
|
|
7346
7607
|
const binary2 = dependencies.scannerBinary ? await dependencies.scannerBinary() : (await new RuntimeStore(stateDir).verifyRuntime("scanner")).entry;
|
|
7347
7608
|
const args2 = ["diagnostics", "diagnostics", "bundle", ...out2 ? ["--out", out2] : [], "--json"];
|
|
7348
|
-
const
|
|
7609
|
+
const stdout2 = await new Promise((resolve3, reject) => {
|
|
7349
7610
|
(dependencies.execFile ?? nodeExecFile2)(
|
|
7350
7611
|
binary2,
|
|
7351
7612
|
args2,
|
|
@@ -7358,14 +7619,14 @@ async function previewDiagnostics(out2, dependencies = {}) {
|
|
|
7358
7619
|
});
|
|
7359
7620
|
let result;
|
|
7360
7621
|
try {
|
|
7361
|
-
result = JSON.parse(
|
|
7622
|
+
result = JSON.parse(stdout2);
|
|
7362
7623
|
} catch {
|
|
7363
7624
|
throw new DiagnosticsError("diagnostics_preview_invalid");
|
|
7364
7625
|
}
|
|
7365
7626
|
if (!validId(result.manifest?.bundleId) || !/^[a-f0-9]{64}$/u.test(result.sha256) || typeof result.path !== "string")
|
|
7366
7627
|
throw new DiagnosticsError("diagnostics_preview_invalid");
|
|
7367
7628
|
const receipt = { schemaVersion: 1, ...result };
|
|
7368
|
-
const receiptPath =
|
|
7629
|
+
const receiptPath = join7(stateDir, "diagnostics", `${result.manifest.bundleId}.json`);
|
|
7369
7630
|
await mkdir3(dirname5(receiptPath), { recursive: true, mode: 448 });
|
|
7370
7631
|
await atomicWrite(receiptPath, Buffer.from(`${JSON.stringify(receipt)}
|
|
7371
7632
|
`));
|
|
@@ -7390,7 +7651,7 @@ async function uploadDiagnosticsBundle(serverUrl, token, bundleId, sha256, bytes
|
|
|
7390
7651
|
async function sendDiagnostics(bundleId, dependencies = {}) {
|
|
7391
7652
|
if (!validId(bundleId)) throw new DiagnosticsError("bundle_id_invalid");
|
|
7392
7653
|
const stateDir = dependencies.stateDir ?? stateDirectory();
|
|
7393
|
-
const receiptPath =
|
|
7654
|
+
const receiptPath = join7(stateDir, "diagnostics", `${bundleId}.json`);
|
|
7394
7655
|
const receipt = JSON.parse(await readFile2(receiptPath, "utf8"));
|
|
7395
7656
|
if (receipt.schemaVersion !== 1 || receipt.manifest?.bundleId !== bundleId || !/^[a-f0-9]{64}$/u.test(receipt.sha256) || typeof receipt.path !== "string" || !(await lstat2(receipt.path)).isFile())
|
|
7396
7657
|
throw new DiagnosticsError("diagnostics_preview_invalid");
|