@wlfi-agent/cli 1.4.16 → 1.4.18
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/Cargo.lock +26 -20
- package/Cargo.toml +1 -1
- package/README.md +61 -28
- package/crates/vault-cli-admin/src/io_utils.rs +149 -1
- package/crates/vault-cli-admin/src/main.rs +639 -16
- package/crates/vault-cli-admin/src/shared_config.rs +18 -18
- package/crates/vault-cli-admin/src/tui/token_rpc.rs +190 -3
- package/crates/vault-cli-admin/src/tui/utils.rs +59 -0
- package/crates/vault-cli-admin/src/tui.rs +1205 -120
- package/crates/vault-cli-agent/Cargo.toml +1 -0
- package/crates/vault-cli-agent/src/io_utils.rs +163 -2
- package/crates/vault-cli-agent/src/main.rs +648 -32
- package/crates/vault-cli-daemon/Cargo.toml +4 -0
- package/crates/vault-cli-daemon/src/main.rs +617 -67
- package/crates/vault-cli-daemon/src/relay_sync.rs +776 -4
- package/crates/vault-cli-daemon/tests/system_keychain_helper_acl.rs +5 -0
- package/crates/vault-daemon/src/daemon_parts/api_impl_and_utils.rs +32 -1
- package/crates/vault-daemon/src/persistence.rs +637 -100
- package/crates/vault-daemon/src/tests.rs +1013 -3
- package/crates/vault-daemon/src/tests_parts/part2.rs +99 -0
- package/crates/vault-daemon/src/tests_parts/part4.rs +11 -7
- package/crates/vault-domain/src/nonce.rs +4 -0
- package/crates/vault-domain/src/tests.rs +616 -0
- package/crates/vault-policy/src/engine.rs +55 -32
- package/crates/vault-policy/src/tests.rs +195 -0
- package/crates/vault-sdk-agent/src/lib.rs +415 -22
- package/crates/vault-signer/Cargo.toml +3 -0
- package/crates/vault-signer/src/lib.rs +266 -40
- package/crates/vault-transport-unix/src/lib.rs +653 -5
- package/crates/vault-transport-xpc/src/tests.rs +531 -3
- package/crates/vault-transport-xpc/tests/e2e_flow.rs +3 -0
- package/dist/cli.cjs +663 -190
- package/dist/cli.cjs.map +1 -1
- package/package.json +5 -2
- package/packages/cache/.turbo/turbo-build.log +53 -52
- package/packages/cache/coverage/clover.xml +529 -394
- package/packages/cache/coverage/coverage-final.json +2 -2
- package/packages/cache/coverage/index.html +21 -21
- package/packages/cache/coverage/src/client/index.html +1 -1
- package/packages/cache/coverage/src/client/index.ts.html +1 -1
- package/packages/cache/coverage/src/errors/index.html +1 -1
- package/packages/cache/coverage/src/errors/index.ts.html +12 -12
- package/packages/cache/coverage/src/index.html +1 -1
- package/packages/cache/coverage/src/index.ts.html +1 -1
- package/packages/cache/coverage/src/service/index.html +21 -21
- package/packages/cache/coverage/src/service/index.ts.html +769 -313
- package/packages/cache/dist/{chunk-QNK6GOTI.js → chunk-KC53LH5Z.js} +35 -2
- package/packages/cache/dist/chunk-KC53LH5Z.js.map +1 -0
- package/packages/cache/dist/{chunk-QF4XKEIA.cjs → chunk-UVU7VFE3.cjs} +35 -2
- package/packages/cache/dist/chunk-UVU7VFE3.cjs.map +1 -0
- package/packages/cache/dist/index.cjs +2 -2
- package/packages/cache/dist/index.js +1 -1
- package/packages/cache/dist/service/index.cjs +2 -2
- package/packages/cache/dist/service/index.js +1 -1
- package/packages/cache/node_modules/.bin/tsc +2 -2
- package/packages/cache/node_modules/.bin/tsserver +2 -2
- package/packages/cache/node_modules/.bin/tsup +2 -2
- package/packages/cache/node_modules/.bin/tsup-node +2 -2
- package/packages/cache/node_modules/.bin/vitest +4 -4
- package/packages/cache/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/cache/src/service/index.test.ts +165 -19
- package/packages/cache/src/service/index.ts +38 -1
- package/packages/config/.turbo/turbo-build.log +18 -17
- package/packages/config/dist/index.cjs +0 -17
- package/packages/config/dist/index.cjs.map +1 -1
- package/packages/config/src/index.ts +0 -17
- package/packages/rpc/.turbo/turbo-build.log +32 -31
- package/packages/rpc/dist/index.cjs +0 -17
- package/packages/rpc/dist/index.cjs.map +1 -1
- package/packages/rpc/src/index.js +1 -0
- package/packages/ui/.turbo/turbo-build.log +44 -43
- package/packages/ui/dist/components/badge.d.ts +1 -1
- package/packages/ui/dist/components/button.d.ts +1 -1
- package/packages/ui/node_modules/.bin/tsc +2 -2
- package/packages/ui/node_modules/.bin/tsserver +2 -2
- package/packages/ui/node_modules/.bin/tsup +2 -2
- package/packages/ui/node_modules/.bin/tsup-node +2 -2
- package/scripts/install-cli-launcher.mjs +37 -0
- package/scripts/install-rust-binaries.mjs +112 -0
- package/scripts/run-tests-isolated.mjs +210 -0
- package/src/cli.ts +310 -50
- package/src/lib/admin-reset.ts +15 -30
- package/src/lib/admin-setup.ts +246 -55
- package/src/lib/agent-auth-migrate.ts +5 -1
- package/src/lib/asset-broadcast.ts +15 -4
- package/src/lib/config-amounts.ts +6 -4
- package/src/lib/hidden-tty-prompt.js +1 -0
- package/src/lib/hidden-tty-prompt.ts +105 -0
- package/src/lib/keychain.ts +1 -0
- package/src/lib/local-admin-access.ts +4 -29
- package/src/lib/rust.ts +129 -33
- package/src/lib/signed-tx.ts +1 -0
- package/src/lib/sudo.ts +15 -5
- package/src/lib/wallet-profile.ts +3 -0
- package/src/lib/wallet-setup.ts +52 -0
- package/packages/cache/dist/chunk-QF4XKEIA.cjs.map +0 -1
- package/packages/cache/dist/chunk-QNK6GOTI.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './index.ts';
|
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
DTS
|
|
35
|
-
DTS
|
|
36
|
-
DTS dist/
|
|
37
|
-
DTS dist/components/
|
|
38
|
-
DTS dist/components/
|
|
39
|
-
DTS dist/components/
|
|
40
|
-
DTS dist/components/
|
|
41
|
-
DTS dist/components/
|
|
42
|
-
DTS dist/components/
|
|
43
|
-
DTS dist/
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @wlfi-agent/ui@0.0.0 build /Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/packages/ui
|
|
4
|
+
> tsup
|
|
5
|
+
|
|
6
|
+
[34mCLI[39m Building entry: src/tailwind.ts, src/components/badge.tsx, src/components/button.tsx, src/components/card.tsx, src/components/input.tsx, src/components/label.tsx, src/components/separator.tsx, src/components/textarea.tsx, src/utils/cn.ts
|
|
7
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
8
|
+
[34mCLI[39m tsup v8.5.1
|
|
9
|
+
[34mCLI[39m Using tsup config: /Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/packages/ui/tsup.config.ts
|
|
10
|
+
[34mCLI[39m Target: es2022
|
|
11
|
+
[34mCLI[39m Cleaning output folder
|
|
12
|
+
[34mESM[39m Build start
|
|
13
|
+
[32mESM[39m [1mdist/utils/cn.js [22m[32m92.00 B[39m
|
|
14
|
+
[32mESM[39m [1mdist/components/badge.js [22m[32m971.00 B[39m
|
|
15
|
+
[32mESM[39m [1mdist/tailwind.js [22m[32m1.59 KB[39m
|
|
16
|
+
[32mESM[39m [1mdist/components/button.js [22m[32m1.43 KB[39m
|
|
17
|
+
[32mESM[39m [1mdist/components/input.js [22m[32m840.00 B[39m
|
|
18
|
+
[32mESM[39m [1mdist/components/label.js [22m[32m327.00 B[39m
|
|
19
|
+
[32mESM[39m [1mdist/components/textarea.js [22m[32m785.00 B[39m
|
|
20
|
+
[32mESM[39m [1mdist/components/card.js [22m[32m1.22 KB[39m
|
|
21
|
+
[32mESM[39m [1mdist/components/separator.js [22m[32m349.00 B[39m
|
|
22
|
+
[32mESM[39m [1mdist/chunk-MOAFBKSA.js [22m[32m209.00 B[39m
|
|
23
|
+
[32mESM[39m [1mdist/tailwind.js.map [22m[32m2.39 KB[39m
|
|
24
|
+
[32mESM[39m [1mdist/utils/cn.js.map [22m[32m71.00 B[39m
|
|
25
|
+
[32mESM[39m [1mdist/components/badge.js.map [22m[32m1.50 KB[39m
|
|
26
|
+
[32mESM[39m [1mdist/components/input.js.map [22m[32m1.12 KB[39m
|
|
27
|
+
[32mESM[39m [1mdist/components/button.js.map [22m[32m2.14 KB[39m
|
|
28
|
+
[32mESM[39m [1mdist/components/separator.js.map [22m[32m519.00 B[39m
|
|
29
|
+
[32mESM[39m [1mdist/components/label.js.map [22m[32m502.00 B[39m
|
|
30
|
+
[32mESM[39m [1mdist/components/textarea.js.map [22m[32m1.05 KB[39m
|
|
31
|
+
[32mESM[39m [1mdist/components/card.js.map [22m[32m2.10 KB[39m
|
|
32
|
+
[32mESM[39m [1mdist/chunk-MOAFBKSA.js.map [22m[32m368.00 B[39m
|
|
33
|
+
[32mESM[39m ⚡️ Build success in 13ms
|
|
34
|
+
DTS Build start
|
|
35
|
+
DTS ⚡️ Build success in 792ms
|
|
36
|
+
DTS dist/tailwind.d.ts 1.49 KB
|
|
37
|
+
DTS dist/components/badge.d.ts 612.00 B
|
|
38
|
+
DTS dist/components/button.d.ts 715.00 B
|
|
39
|
+
DTS dist/components/card.d.ts 791.00 B
|
|
40
|
+
DTS dist/components/input.d.ts 191.00 B
|
|
41
|
+
DTS dist/components/label.d.ts 165.00 B
|
|
42
|
+
DTS dist/components/separator.d.ts 166.00 B
|
|
43
|
+
DTS dist/components/textarea.d.ts 206.00 B
|
|
44
|
+
DTS dist/utils/cn.d.ts 106.00 B
|
|
@@ -3,7 +3,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
|
|
5
5
|
declare const badgeVariants: (props?: ({
|
|
6
|
-
variant?: "default" | "secondary" | "
|
|
6
|
+
variant?: "default" | "secondary" | "destructive" | "success" | "warning" | null | undefined;
|
|
7
7
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
8
8
|
interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
9
9
|
}
|
|
@@ -3,7 +3,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "default" | "secondary" | "
|
|
6
|
+
variant?: "default" | "secondary" | "outline" | "ghost" | "destructive" | null | undefined;
|
|
7
7
|
size?: "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir
|
|
14
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir
|
|
16
|
+
exec node "$basedir/../typescript/bin/tsc" "$@"
|
|
17
17
|
fi
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/typescript@5.9.3/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir
|
|
14
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir
|
|
16
|
+
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
|
17
17
|
fi
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir
|
|
14
|
+
exec "$basedir/node" "$basedir/../tsup/dist/cli-default.js" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir
|
|
16
|
+
exec node "$basedir/../tsup/dist/cli-default.js" "$@"
|
|
17
17
|
fi
|
|
@@ -11,7 +11,7 @@ else
|
|
|
11
11
|
export NODE_PATH="/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/dist/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/tsup@8.5.1_jiti@1.21.7_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3/node_modules:/Users/hanzhi/Documents/WLFI/wlfi-agent-sdk/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
12
12
|
fi
|
|
13
13
|
if [ -x "$basedir/node" ]; then
|
|
14
|
-
exec "$basedir/node" "$basedir
|
|
14
|
+
exec "$basedir/node" "$basedir/../tsup/dist/cli-node.js" "$@"
|
|
15
15
|
else
|
|
16
|
-
exec node "$basedir
|
|
16
|
+
exec node "$basedir/../tsup/dist/cli-node.js" "$@"
|
|
17
17
|
fi
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { installCliLauncher } from './install-rust-binaries.mjs';
|
|
5
|
+
|
|
6
|
+
function resolveWlfiHome(env) {
|
|
7
|
+
return env.WLFI_HOME?.trim() || path.join(os.homedir(), '.wlfi_agent');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function installLocalCliLauncher({
|
|
11
|
+
env = process.env,
|
|
12
|
+
platform = process.platform,
|
|
13
|
+
cliEntrypoint,
|
|
14
|
+
} = {}) {
|
|
15
|
+
const wlfiHome = resolveWlfiHome(env);
|
|
16
|
+
const binDir = path.join(wlfiHome, 'bin');
|
|
17
|
+
return installCliLauncher({ binDir, platform, cliEntrypoint });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isDirectExecution() {
|
|
21
|
+
return (
|
|
22
|
+
Boolean(process.argv[1]) &&
|
|
23
|
+
import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isDirectExecution()) {
|
|
28
|
+
try {
|
|
29
|
+
installLocalCliLauncher();
|
|
30
|
+
} catch (error) {
|
|
31
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
32
|
+
process.stderr.write(`${message}\n`);
|
|
33
|
+
process.exitCode = 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { installLocalCliLauncher };
|
|
@@ -6,6 +6,11 @@ import { pathToFileURL } from 'node:url';
|
|
|
6
6
|
|
|
7
7
|
const repoRoot = new URL('..', import.meta.url).pathname;
|
|
8
8
|
const extension = process.platform === 'win32' ? '.exe' : '';
|
|
9
|
+
const MIN_RUST_VERSION = {
|
|
10
|
+
major: 1,
|
|
11
|
+
minor: 87,
|
|
12
|
+
patch: 0,
|
|
13
|
+
};
|
|
9
14
|
const rustBins = [
|
|
10
15
|
'wlfi-agent-daemon',
|
|
11
16
|
'wlfi-agent-admin',
|
|
@@ -22,6 +27,32 @@ function decodeOutput(value) {
|
|
|
22
27
|
return value.toString().trim();
|
|
23
28
|
}
|
|
24
29
|
|
|
30
|
+
function formatMinimumRustVersion() {
|
|
31
|
+
return `${MIN_RUST_VERSION.major}.${MIN_RUST_VERSION.minor}.${MIN_RUST_VERSION.patch}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseRustVersion(output) {
|
|
35
|
+
const match = output.match(/\b(\d+)\.(\d+)\.(\d+)(?:[-+][^\s]+)?\b/);
|
|
36
|
+
if (!match) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
major: Number(match[1]),
|
|
41
|
+
minor: Number(match[2]),
|
|
42
|
+
patch: Number(match[3]),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function compareVersions(left, right) {
|
|
47
|
+
if (left.major !== right.major) {
|
|
48
|
+
return left.major - right.major;
|
|
49
|
+
}
|
|
50
|
+
if (left.minor !== right.minor) {
|
|
51
|
+
return left.minor - right.minor;
|
|
52
|
+
}
|
|
53
|
+
return left.patch - right.patch;
|
|
54
|
+
}
|
|
55
|
+
|
|
25
56
|
function runCheck(spawnSyncImpl, command, args, options = {}) {
|
|
26
57
|
return spawnSyncImpl(command, args, {
|
|
27
58
|
cwd: repoRoot,
|
|
@@ -55,6 +86,53 @@ function resolveHelperScripts(binDir) {
|
|
|
55
86
|
];
|
|
56
87
|
}
|
|
57
88
|
|
|
89
|
+
function resolveCliEntrypoint() {
|
|
90
|
+
return path.join(repoRoot, 'dist', 'cli.cjs');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function escapePosixShellArgument(value) {
|
|
94
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function installCliLauncher({
|
|
98
|
+
binDir,
|
|
99
|
+
cliEntrypoint = resolveCliEntrypoint(),
|
|
100
|
+
platform = process.platform,
|
|
101
|
+
allowMissingEntrypoint = false,
|
|
102
|
+
} = {}) {
|
|
103
|
+
if (!binDir) {
|
|
104
|
+
throw new Error('[wlfi-agent] binDir is required to install the CLI launcher.');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
fs.mkdirSync(binDir, { recursive: true, mode: 0o700 });
|
|
108
|
+
|
|
109
|
+
if (!fs.existsSync(cliEntrypoint)) {
|
|
110
|
+
if (allowMissingEntrypoint) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
throw new Error(
|
|
114
|
+
`[wlfi-agent] CLI entrypoint was not found at ${cliEntrypoint}. Run \`npm run build\` first.`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (platform === 'win32') {
|
|
119
|
+
const destination = path.join(binDir, 'wlfi-agent.cmd');
|
|
120
|
+
const escaped = cliEntrypoint.replace(/"/g, '""');
|
|
121
|
+
fs.writeFileSync(destination, `@echo off\r\nnode "${escaped}" %*\r\n`, {
|
|
122
|
+
mode: 0o755,
|
|
123
|
+
});
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const destination = path.join(binDir, 'wlfi-agent');
|
|
128
|
+
const script =
|
|
129
|
+
'#!/bin/sh\n' +
|
|
130
|
+
`exec node ${escapePosixShellArgument(cliEntrypoint)} "$@"\n`;
|
|
131
|
+
fs.writeFileSync(destination, script, { mode: 0o755 });
|
|
132
|
+
fs.chmodSync(destination, 0o755);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
|
|
58
136
|
function checkCargoAvailable(spawnSyncImpl) {
|
|
59
137
|
const result = runCheck(spawnSyncImpl, 'cargo', ['--version']);
|
|
60
138
|
if (result.status === 0) {
|
|
@@ -73,6 +151,38 @@ function checkCargoAvailable(spawnSyncImpl) {
|
|
|
73
151
|
throw new Error(lines.join('\n'));
|
|
74
152
|
}
|
|
75
153
|
|
|
154
|
+
function checkRustcVersion(spawnSyncImpl) {
|
|
155
|
+
const result = runCheck(spawnSyncImpl, 'rustc', ['--version']);
|
|
156
|
+
if (result.status !== 0) {
|
|
157
|
+
const detail = decodeOutput(result.stderr) || decodeOutput(result.stdout);
|
|
158
|
+
const lines = [
|
|
159
|
+
'[wlfi-agent] Rust compiler was not found on PATH.',
|
|
160
|
+
`[wlfi-agent] Install Rust ${formatMinimumRustVersion()} or newer from https://rustup.rs.`,
|
|
161
|
+
];
|
|
162
|
+
if (detail) {
|
|
163
|
+
lines.push(`[wlfi-agent] rustc check output: ${detail}`);
|
|
164
|
+
}
|
|
165
|
+
lines.push(`[wlfi-agent] ${RERUN_INSTRUCTIONS}`);
|
|
166
|
+
throw new Error(lines.join('\n'));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const versionOutput = decodeOutput(result.stdout) || decodeOutput(result.stderr);
|
|
170
|
+
const parsedVersion = parseRustVersion(versionOutput);
|
|
171
|
+
if (!parsedVersion) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`[wlfi-agent] Unable to determine the installed Rust compiler version from: ${versionOutput || '<empty output>'}`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (compareVersions(parsedVersion, MIN_RUST_VERSION) < 0) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`[wlfi-agent] Rust ${formatMinimumRustVersion()} or newer is required; found ${versionOutput}.\n` +
|
|
180
|
+
`[wlfi-agent] Update Rust with \`rustup update\`.\n` +
|
|
181
|
+
`[wlfi-agent] ${RERUN_INSTRUCTIONS}`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
76
186
|
function checkMacOsToolchainAvailable(spawnSyncImpl, platform) {
|
|
77
187
|
if (platform !== 'darwin') {
|
|
78
188
|
return;
|
|
@@ -100,6 +210,7 @@ export function verifyRustInstallPrerequisites({
|
|
|
100
210
|
platform = process.platform,
|
|
101
211
|
} = {}) {
|
|
102
212
|
checkCargoAvailable(spawnSyncImpl);
|
|
213
|
+
checkRustcVersion(spawnSyncImpl);
|
|
103
214
|
checkMacOsToolchainAvailable(spawnSyncImpl, platform);
|
|
104
215
|
}
|
|
105
216
|
|
|
@@ -122,6 +233,7 @@ export function installRustBinaries({
|
|
|
122
233
|
'cargo',
|
|
123
234
|
[
|
|
124
235
|
'build',
|
|
236
|
+
'--locked',
|
|
125
237
|
'--release',
|
|
126
238
|
'-p',
|
|
127
239
|
'wlfi-agent-daemon',
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
|
|
8
|
+
function fail(message) {
|
|
9
|
+
console.error(message);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const forwardedArgs = process.argv.slice(2);
|
|
14
|
+
const commandArgs =
|
|
15
|
+
forwardedArgs[0] === '--' ? forwardedArgs.slice(1) : forwardedArgs;
|
|
16
|
+
|
|
17
|
+
if (commandArgs.length === 0) {
|
|
18
|
+
fail(
|
|
19
|
+
'usage: node ./scripts/run-tests-isolated.mjs -- <command> [args...]',
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const hostHome = process.env.HOME;
|
|
24
|
+
const sandboxBaseDir = hostHome ? path.join(hostHome, '.wt') : os.tmpdir();
|
|
25
|
+
fs.mkdirSync(sandboxBaseDir, { recursive: true, mode: 0o700 });
|
|
26
|
+
const sandboxRoot = fs.mkdtempSync(path.join(sandboxBaseDir, 't-'));
|
|
27
|
+
const homeDir = path.join(sandboxRoot, 'h');
|
|
28
|
+
const wlfiHome = path.join(sandboxRoot, 'w');
|
|
29
|
+
const tmpDir = path.join(sandboxRoot, 't');
|
|
30
|
+
const binDir = path.join(sandboxRoot, 'b');
|
|
31
|
+
const fakeKeychainRoot = path.join(sandboxRoot, 'k');
|
|
32
|
+
const keepSandbox = process.env.WLFI_TEST_KEEP_SANDBOX === '1';
|
|
33
|
+
const cargoHome =
|
|
34
|
+
process.env.CARGO_HOME ?? (hostHome ? path.join(hostHome, '.cargo') : undefined);
|
|
35
|
+
const rustupHome =
|
|
36
|
+
process.env.RUSTUP_HOME ?? (hostHome ? path.join(hostHome, '.rustup') : undefined);
|
|
37
|
+
const xdgCacheHome = path.join(sandboxRoot, 'c');
|
|
38
|
+
const xdgConfigHome = path.join(sandboxRoot, 'g');
|
|
39
|
+
|
|
40
|
+
for (const dir of [
|
|
41
|
+
homeDir,
|
|
42
|
+
wlfiHome,
|
|
43
|
+
tmpDir,
|
|
44
|
+
binDir,
|
|
45
|
+
fakeKeychainRoot,
|
|
46
|
+
xdgCacheHome,
|
|
47
|
+
xdgConfigHome,
|
|
48
|
+
]) {
|
|
49
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function writeExecutable(targetPath, contents) {
|
|
53
|
+
fs.writeFileSync(targetPath, contents, { mode: 0o755 });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
writeExecutable(
|
|
57
|
+
path.join(binDir, 'security'),
|
|
58
|
+
`#!/usr/bin/env node
|
|
59
|
+
import fs from 'node:fs';
|
|
60
|
+
import path from 'node:path';
|
|
61
|
+
|
|
62
|
+
const root = process.env.WLFI_TEST_FAKE_KEYCHAIN_ROOT;
|
|
63
|
+
if (!root) {
|
|
64
|
+
console.error('WLFI_TEST_FAKE_KEYCHAIN_ROOT is required');
|
|
65
|
+
process.exit(70);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const dbPath = path.join(root, 'keychain.json');
|
|
69
|
+
const [command, ...args] = process.argv.slice(2);
|
|
70
|
+
|
|
71
|
+
function loadDb() {
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(fs.readFileSync(dbPath, 'utf8'));
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (error && typeof error === 'object' && error.code === 'ENOENT') {
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function saveDb(db) {
|
|
83
|
+
fs.writeFileSync(dbPath, JSON.stringify(db, null, 2) + '\\n', { mode: 0o600 });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function readFlag(flag) {
|
|
87
|
+
const index = args.indexOf(flag);
|
|
88
|
+
if (index === -1 || index === args.length - 1) {
|
|
89
|
+
console.error('isolated security shim requires ' + flag);
|
|
90
|
+
process.exit(64);
|
|
91
|
+
}
|
|
92
|
+
return args[index + 1];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const service = readFlag('-s');
|
|
96
|
+
const account = readFlag('-a');
|
|
97
|
+
const key = service + '\\u0000' + account;
|
|
98
|
+
const db = loadDb();
|
|
99
|
+
|
|
100
|
+
switch (command) {
|
|
101
|
+
case 'add-generic-password': {
|
|
102
|
+
const secretHex = readFlag('-X');
|
|
103
|
+
db[key] = Buffer.from(secretHex, 'hex').toString('utf8');
|
|
104
|
+
saveDb(db);
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
case 'find-generic-password': {
|
|
108
|
+
if (!(key in db)) {
|
|
109
|
+
console.error('The specified item could not be found in the keychain.');
|
|
110
|
+
process.exit(44);
|
|
111
|
+
}
|
|
112
|
+
process.stdout.write(String(db[key]));
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
case 'delete-generic-password': {
|
|
116
|
+
if (!(key in db)) {
|
|
117
|
+
console.error('The specified item could not be found in the keychain.');
|
|
118
|
+
process.exit(44);
|
|
119
|
+
}
|
|
120
|
+
delete db[key];
|
|
121
|
+
saveDb(db);
|
|
122
|
+
process.exit(0);
|
|
123
|
+
}
|
|
124
|
+
default:
|
|
125
|
+
console.error('isolated security shim does not implement: ' + command);
|
|
126
|
+
process.exit(64);
|
|
127
|
+
}
|
|
128
|
+
`,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
for (const commandName of ['sudo', 'launchctl']) {
|
|
132
|
+
writeExecutable(
|
|
133
|
+
path.join(binDir, commandName),
|
|
134
|
+
`#!/bin/sh
|
|
135
|
+
echo "isolated test harness blocked real ${commandName}; inject a test double if this path is expected" >&2
|
|
136
|
+
exit 99
|
|
137
|
+
`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const child = spawn(commandArgs[0], commandArgs.slice(1), {
|
|
142
|
+
stdio: 'inherit',
|
|
143
|
+
env: {
|
|
144
|
+
...process.env,
|
|
145
|
+
HOME: homeDir,
|
|
146
|
+
WLFI_HOME: wlfiHome,
|
|
147
|
+
TMPDIR: tmpDir,
|
|
148
|
+
XDG_CACHE_HOME: xdgCacheHome,
|
|
149
|
+
XDG_CONFIG_HOME: xdgConfigHome,
|
|
150
|
+
PATH: `${binDir}${path.delimiter}${process.env.PATH ?? ''}`,
|
|
151
|
+
WLFI_TEST_FAKE_KEYCHAIN_ROOT: fakeKeychainRoot,
|
|
152
|
+
WLFI_TEST_SANDBOX_ROOT: sandboxRoot,
|
|
153
|
+
WLFI_TEST_ISOLATED: '1',
|
|
154
|
+
...(cargoHome ? { CARGO_HOME: cargoHome } : {}),
|
|
155
|
+
...(rustupHome ? { RUSTUP_HOME: rustupHome } : {}),
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
let cleanedUp = false;
|
|
160
|
+
|
|
161
|
+
function cleanup() {
|
|
162
|
+
if (cleanedUp) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
cleanedUp = true;
|
|
166
|
+
|
|
167
|
+
if (keepSandbox) {
|
|
168
|
+
console.error(`kept test sandbox: ${sandboxRoot}`);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
fs.rmSync(sandboxRoot, { recursive: true, force: true });
|
|
173
|
+
try {
|
|
174
|
+
fs.rmdirSync(sandboxBaseDir);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
if (!error || typeof error !== 'object') {
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
if (!('code' in error) || (error.code !== 'ENOENT' && error.code !== 'ENOTEMPTY')) {
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const signalExitCodes = {
|
|
186
|
+
SIGHUP: 129,
|
|
187
|
+
SIGINT: 130,
|
|
188
|
+
SIGTERM: 143,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
for (const signal of Object.keys(signalExitCodes)) {
|
|
192
|
+
process.on(signal, () => {
|
|
193
|
+
if (!child.killed) {
|
|
194
|
+
child.kill(signal);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
child.on('error', (error) => {
|
|
200
|
+
cleanup();
|
|
201
|
+
fail(`failed to start isolated test command: ${error.message}`);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
child.on('exit', (code, signal) => {
|
|
205
|
+
cleanup();
|
|
206
|
+
if (signal) {
|
|
207
|
+
process.exit(signalExitCodes[signal] ?? 1);
|
|
208
|
+
}
|
|
209
|
+
process.exit(code ?? 1);
|
|
210
|
+
});
|