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()) && (stat.mode & 0o777) === mode;
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "larkin",
3
- "version": "0.2.79",
3
+ "version": "0.2.81",
4
4
  "private": false,
5
5
  "larkinPackageRole": "npm-published",
6
6
  "files": [