larkin 0.2.79 → 0.2.81
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.
|
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import crypto from "node:crypto";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { isWindows, secureWindowsDirectoryAcl } from "../platform/secure-metadata.mjs";
|
|
5
6
|
// proper-lockfile does not publish TypeScript declarations.
|
|
6
7
|
// @ts-expect-error bundled CommonJS dependency
|
|
7
8
|
import properLockfile from "proper-lockfile";
|
|
@@ -22,6 +23,11 @@ function ensureLockDirectory(lockPath) {
|
|
|
22
23
|
const directory = path.dirname(lockPath);
|
|
23
24
|
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
24
25
|
fs.chmodSync(directory, 0o700);
|
|
26
|
+
if (isWindows) {
|
|
27
|
+
// Windows 无 POSIX 权限位(mode 恒 0o666):改用 icacls 收紧 ACL 并回读校验。
|
|
28
|
+
secureWindowsDirectoryAcl(directory, { label: "Pi credential lock 目录" });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
25
31
|
const stat = fs.lstatSync(directory);
|
|
26
32
|
if (!stat.isDirectory() || stat.isSymbolicLink()
|
|
27
33
|
|| (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
@@ -85,6 +91,11 @@ function ensurePrivateDirectory(directory) {
|
|
|
85
91
|
fs.chmodSync(path.dirname(directory), 0o700);
|
|
86
92
|
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
87
93
|
fs.chmodSync(directory, 0o700);
|
|
94
|
+
if (isWindows) {
|
|
95
|
+
// Windows 无 POSIX 权限位:icacls 收紧为「当前用户 + SYSTEM」并回读校验。
|
|
96
|
+
secureWindowsDirectoryAcl(directory, { label: "Pi official credential 目录" });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
88
99
|
const stat = fs.lstatSync(directory);
|
|
89
100
|
if (!stat.isDirectory() || stat.isSymbolicLink()
|
|
90
101
|
|| (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
@@ -97,7 +108,7 @@ function safeRead(file) {
|
|
|
97
108
|
const stat = fs.lstatSync(file);
|
|
98
109
|
if (!stat.isFile() || stat.isSymbolicLink()
|
|
99
110
|
|| (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
100
|
-
|| (stat.mode & 0o777) !== 0o600)
|
|
111
|
+
|| (!isWindows && (stat.mode & 0o777) !== 0o600))
|
|
101
112
|
throw new Error(`unsafe Pi auth file: ${path.basename(file)}`);
|
|
102
113
|
return fs.readFileSync(file);
|
|
103
114
|
}
|
|
@@ -14,6 +14,7 @@ exports.stageBuiltinPiProvider = stageBuiltinPiProvider;
|
|
|
14
14
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
15
15
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
16
16
|
const node_path_1 = __importDefault(require("node:path"));
|
|
17
|
+
const secure_metadata_js_1 = require("../platform/secure-metadata.cjs");
|
|
17
18
|
exports.BUNDLED_PI_VERSION = "0.83.0";
|
|
18
19
|
// These values mirror the catalog shipped by the pinned official Pi distribution.
|
|
19
20
|
// Keeping the user-facing defaults here makes endpoint changes reviewable in Larkin.
|
|
@@ -95,6 +96,11 @@ function piAgentDirectory(configDir, agentId) {
|
|
|
95
96
|
return node_path_1.default.join(node_path_1.default.resolve(configDir), "providers", "pi", agentId);
|
|
96
97
|
}
|
|
97
98
|
function assertPrivateDirectory(directory) {
|
|
99
|
+
if (secure_metadata_js_1.isWindows) {
|
|
100
|
+
// Windows 无 POSIX 权限位:icacls 收紧为「当前用户 + SYSTEM」并回读校验。
|
|
101
|
+
(0, secure_metadata_js_1.secureWindowsDirectoryAcl)(directory, { label: "Pi provider 凭证目录" });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
98
104
|
const stat = node_fs_1.default.lstatSync(directory);
|
|
99
105
|
if (!stat.isDirectory() || stat.isSymbolicLink()
|
|
100
106
|
|| (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
@@ -129,7 +135,7 @@ function readSnapshot(file) {
|
|
|
129
135
|
const stat = node_fs_1.default.lstatSync(file);
|
|
130
136
|
if (!stat.isFile() || stat.isSymbolicLink()
|
|
131
137
|
|| (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
132
|
-
|| (stat.mode & 0o777) !== 0o600)
|
|
138
|
+
|| (!secure_metadata_js_1.isWindows && (stat.mode & 0o777) !== 0o600))
|
|
133
139
|
throw new Error(`Pi provider 文件不安全: ${node_path_1.default.basename(file)}`);
|
|
134
140
|
return node_fs_1.default.readFileSync(file);
|
|
135
141
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { isWindows, secureWindowsDirectoryAcl } from "../platform/secure-metadata.mjs";
|
|
4
5
|
export const BUNDLED_PI_VERSION = "0.83.0";
|
|
5
6
|
// These values mirror the catalog shipped by the pinned official Pi distribution.
|
|
6
7
|
// Keeping the user-facing defaults here makes endpoint changes reviewable in Larkin.
|
|
@@ -82,6 +83,11 @@ export function piAgentDirectory(configDir, agentId) {
|
|
|
82
83
|
return path.join(path.resolve(configDir), "providers", "pi", agentId);
|
|
83
84
|
}
|
|
84
85
|
function assertPrivateDirectory(directory) {
|
|
86
|
+
if (isWindows) {
|
|
87
|
+
// Windows 无 POSIX 权限位:icacls 收紧为「当前用户 + SYSTEM」并回读校验。
|
|
88
|
+
secureWindowsDirectoryAcl(directory, { label: "Pi provider 凭证目录" });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
85
91
|
const stat = fs.lstatSync(directory);
|
|
86
92
|
if (!stat.isDirectory() || stat.isSymbolicLink()
|
|
87
93
|
|| (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
@@ -116,7 +122,7 @@ function readSnapshot(file) {
|
|
|
116
122
|
const stat = fs.lstatSync(file);
|
|
117
123
|
if (!stat.isFile() || stat.isSymbolicLink()
|
|
118
124
|
|| (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
119
|
-
|| (stat.mode & 0o777) !== 0o600)
|
|
125
|
+
|| (!isWindows && (stat.mode & 0o777) !== 0o600))
|
|
120
126
|
throw new Error(`Pi provider 文件不安全: ${path.basename(file)}`);
|
|
121
127
|
return fs.readFileSync(file);
|
|
122
128
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { isWindows } from "../platform/secure-metadata.mjs";
|
|
3
4
|
import { callbackCapability, documentCommentReplyCapability, documentCommentSubscriptionCapability, } from "../platform/callback-capability.mjs";
|
|
4
5
|
const BOT_CREDENTIAL_FIELDS = new Set(["appId", "appSecret", "tenant", "ownerOpenId", "createdAt", "updatedAt", "capabilities"]);
|
|
5
6
|
function validDocumentCommentCapability(value) {
|
|
@@ -50,7 +51,8 @@ export function validCredentialRecord(value, appId) {
|
|
|
50
51
|
return true;
|
|
51
52
|
}
|
|
52
53
|
function isOwnedWithExactMode(stat, mode) {
|
|
53
|
-
return (typeof process.getuid !== "function" || stat.uid === process.getuid())
|
|
54
|
+
return (typeof process.getuid !== "function" || stat.uid === process.getuid())
|
|
55
|
+
&& (isWindows || (stat.mode & 0o777) === mode);
|
|
54
56
|
}
|
|
55
57
|
export function assertSecureBotsDirectory(botsDir) {
|
|
56
58
|
const stat = fs.lstatSync(botsDir);
|
|
@@ -6,6 +6,7 @@ import fs from "node:fs";
|
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import readline from "node:readline";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { isWindows } from "../platform/secure-metadata.mjs";
|
|
9
10
|
import { TargetRootLayout } from "../platform/root-layout.mjs";
|
|
10
11
|
import { planSingleRootBinding } from "./setup-binding.mjs";
|
|
11
12
|
import { discoverPiModelCatalog } from "../runtime/pi-model-catalog.mjs";
|
|
@@ -126,7 +127,7 @@ function readSetupSelection(fileArg) {
|
|
|
126
127
|
const stat = fs.lstatSync(file);
|
|
127
128
|
if (!stat.isFile() || stat.isSymbolicLink()
|
|
128
129
|
|| (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
129
|
-
|| (stat.mode & 0o777) !== 0o600)
|
|
130
|
+
|| (!isWindows && (stat.mode & 0o777) !== 0o600))
|
|
130
131
|
die("setup Agent 选择文件必须是当前用户拥有的 0600 普通文件");
|
|
131
132
|
const bytes = fs.readFileSync(file, "utf8");
|
|
132
133
|
fs.unlinkSync(file);
|