@vibe-lark/larkpal 0.1.84 → 0.1.86
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/account-id-BM1T6029-DYjVxojW.mjs +46 -0
- package/dist/activation-context--5yu1dPF-Bwsn3moT.mjs +172 -0
- package/dist/anthropic-TH8ERTXK.mjs +5962 -0
- package/dist/assistant-visible-text-DuFWokAt-CsbII5KS.mjs +596 -0
- package/dist/azure-openai-responses-Bt_Ag9Er.mjs +166 -0
- package/dist/boundary-file-read-BSd9MXPy--KThL5e6.mjs +594 -0
- package/dist/browser-lifecycle-cleanup-BdNsMhMD-O3tnAM4i.mjs +60 -0
- package/dist/build-DgTrEpge.mjs +3333 -0
- package/dist/bundled-compat-BpaDaAAu-D7oazKjD.mjs +5216 -0
- package/dist/bundled-dir-U738ay4K-DXK0q_TV.mjs +258 -0
- package/dist/call-DimWbpgJ-ColD4W-y.mjs +9993 -0
- package/dist/channel-bootstrap.runtime-BVclcGv1-DJv_Z-Kr.mjs +2 -0
- package/dist/channel-bootstrap.runtime-Cwcr38m2-VRfVCR-i.mjs +33 -0
- package/dist/chunk-D6SyT4dJ.mjs +36 -0
- package/dist/cli.mjs +6 -6
- package/dist/command-format-LSnUCVVF-BQ2SMKka.mjs +685 -0
- package/dist/config-Bim2pi8a-BQUdfiEi.mjs +9 -0
- package/dist/delivery-context.shared-j5hC5qb1-CI83RXXZ.mjs +72 -0
- package/dist/diagnostic-ClMwNnUA-D6nUtLnb.mjs +140 -0
- package/dist/dist-CEGw8-2W.mjs +429 -0
- package/dist/dist-DD2aJ2UL.mjs +125135 -0
- package/dist/env-api-keys-BVvSg7T2.mjs +68 -0
- package/dist/event-stream-xaQWmyas.mjs +15226 -0
- package/dist/facade-loader-DFzIYYt_-CIr4HKtE.mjs +194 -0
- package/dist/from-DF7cl2wz.mjs +3842 -0
- package/dist/gateway-method-policy-C7rf0SeV-CJQMEYIE.mjs +28 -0
- package/dist/github-copilot-headers-DjqWtUoP.mjs +22 -0
- package/dist/google-C2pVrgBZ.mjs +336 -0
- package/dist/google-gemini-cli-BBxgS5Ho.mjs +623 -0
- package/dist/google-shared-BsWgwEk1.mjs +22791 -0
- package/dist/google-vertex-BsVLJrrC.mjs +358 -0
- package/dist/hash-DAFtW_W7.mjs +16 -0
- package/dist/headers-R3HdCbAE.mjs +8 -0
- package/dist/home-dir-C44RaPME-CBRS4HLP.mjs +93 -0
- package/dist/ids-BPsM98Uu-CwuxvUai.mjs +77 -0
- package/dist/image-2w3cApg7-CxpHvoB5.mjs +207 -0
- package/dist/io-CH2g3vsv-BOGlLlB8.mjs +26218 -0
- package/dist/jiti-loader-cache-Bat69wam-D6hCxboy.mjs +5049 -0
- package/dist/json-file-BQRNuxmK-DhJM5NsG.mjs +108 -0
- package/dist/json-parse-v_HIJjjI.mjs +381 -0
- package/dist/jws-GFcTvvVT.mjs +2291 -0
- package/dist/{lark-cli-provider-7LvtOIF_.mjs → lark-cli-provider-BARgbbmo.mjs} +1 -1
- package/dist/{live-smoke-nvTUPtrv.mjs → live-smoke-BhkBOcH9.mjs} +3 -3
- package/dist/load-context-mb7uvLSn-B10MAi3I.mjs +29 -0
- package/dist/loader-708jrx4Y-BOswuvpe.mjs +5053 -0
- package/dist/main.mjs +56780 -476
- package/dist/manifest-registry-_hxKCS2K-CZdeyN0f.mjs +3512 -0
- package/dist/mcp-server.mjs +1 -1
- package/dist/message-channel-Bk_YHfQg-AeNrPPpp.mjs +50 -0
- package/dist/message-channel-core-DTA--Gjh-CY4Tkb7N.mjs +29 -0
- package/dist/message.config.runtime-K-k4XOyq-DZTmXomP.mjs +2 -0
- package/dist/message.gateway.runtime-DqHOHRTQ-DH4ml0YF.mjs +2 -0
- package/dist/mistral-CaR4DiLu.mjs +28657 -0
- package/dist/model-auth-env-oyg2Hexc-DU_rOUU5.mjs +1306 -0
- package/dist/models-config-BmpSQJQF-Gfvh1n3A.mjs +1282 -0
- package/dist/models-config.runtime-BsU_22xk.mjs +2 -0
- package/dist/multipart-parser-DedmaB5g.mjs +294 -0
- package/dist/oauth-DOJeGfcE.mjs +6392 -0
- package/dist/openai-BDtIh3Ja.mjs +6693 -0
- package/dist/openai-codex-responses-C5EORu31.mjs +664 -0
- package/dist/openai-completions-CR_cS6gX.mjs +669 -0
- package/dist/openai-responses-oGxwZyuC.mjs +184 -0
- package/dist/openai-responses-shared-BixMSDZE.mjs +398 -0
- package/dist/paths-D6msg0S1-C2lYuisN.mjs +189 -0
- package/dist/paths-D92DjaZ--CTOESW2b.mjs +192 -0
- package/dist/pi-model-discovery-Bd0TWzo8-BFsJmeMb.mjs +227 -0
- package/dist/pi-model-discovery-runtime-CCCZxkd8.mjs +2 -0
- package/dist/pi-tools.before-tool-call.runtime-Bn7uqKie-C5ewk8kK.mjs +399 -0
- package/dist/plugin-auto-enable-DdH3n9V8-DsA1isaF.mjs +1456 -0
- package/dist/process-scoped-map-B2cWkYET-CXwUZ8CZ.mjs +61 -0
- package/dist/provider-discovery.runtime-BPzz1PFj.mjs +58 -0
- package/dist/provider-model-compat-CFqcq0it-BDDuBI3A.mjs +118 -0
- package/dist/provider-runtime-C8rljsNs-CIT93zoy.mjs +2 -0
- package/dist/provider-runtime-CT50mNIX-BwEV6GyO.mjs +573 -0
- package/dist/provider-stream-COLujAAo-CbJPDngm.mjs +35449 -0
- package/dist/providers.runtime-Ba7tOlq7-CXkhkzU9.mjs +219 -0
- package/dist/public-surface-loader-BVl0NQAE-C0piXtsT.mjs +117 -0
- package/dist/resolve-C33B7eeu-BNvYTl6k.mjs +1041 -0
- package/dist/runtime-Cym-fqI8-DaSDMH-a.mjs +120 -0
- package/dist/runtime-channel-state-CohMybAh-hXR6y5Gx.mjs +19 -0
- package/dist/runtime-snapshot-C54O1-gI-40cbyi7P.mjs +677 -0
- package/dist/runtime-state-IBOIXKOx-Bf9tcLvc.mjs +10 -0
- package/dist/runtime-web-tools-fallback.runtime-Ca-qn1mj-BCVImm7a.mjs +39 -0
- package/dist/runtime-web-tools-manifest.runtime-BgxQTjmq-Cb4nJkRT.mjs +2 -0
- package/dist/runtime-web-tools-public-artifacts.runtime-D9qcoWIX-BrQdXzOQ.mjs +2 -0
- package/dist/session-archive.runtime-B52_5vs4-BG-_IwNJ.mjs +2 -0
- package/dist/session-key-Cn2QoOyX-CuHbJMgR.mjs +82 -0
- package/dist/session-transcript-files.fs-DEeFXruQ-B1PF6nLy.mjs +147 -0
- package/dist/src-BgCX0MLG.mjs +813 -0
- package/dist/src-DYbqlAqf.mjs +1177 -0
- package/dist/subagent-announce-L5WsQatW-CQWI9GMd.mjs +344 -0
- package/dist/subagent-announce.registry.runtime-DiqZyeTs-BKuniyi3.mjs +28 -0
- package/dist/subagent-registry-steer-runtime-DFgZFC0j-BhBz0roy.mjs +211 -0
- package/dist/subagent-system-prompt-C1qnN--K-DpnTFP47.mjs +3061 -0
- package/dist/target-parsing-loaded-DKkb6jJY-BMD4CkpS.mjs +1002 -0
- package/dist/task-registry-delivery-runtime-Dd1CUkZF-C8U40a3O.mjs +2950 -0
- package/dist/task-registry-delivery-runtime-ragbeVx5-CNbFAkjD.mjs +2 -0
- package/dist/thinking-Bh-7MqXz-D3woGbO7.mjs +2 -0
- package/dist/transcript-E_-ISOkD-DWCfZP2p.mjs +2019 -0
- package/dist/transcript.runtime-BqhvZZdl-BPy42vBP.mjs +2 -0
- package/dist/transform-messages-DbhIzTxq.mjs +207 -0
- package/dist/web-provider-public-artifacts-BlpRwIUS-CGPSV4W2.mjs +295 -0
- package/dist/web-search-providers.runtime--0aUtC3b-DyuhC95V.mjs +200 -0
- package/package.json +3 -3
- package/dist/rolldown-runtime-wcPFST8Q.mjs +0 -13
- /package/dist/{interactive-init-B6j8j_Ap.mjs → interactive-init-BXQBalNr.mjs} +0 -0
|
@@ -0,0 +1,1041 @@
|
|
|
1
|
+
import { o as normalizeLowercaseStringOrEmpty } from "./home-dir-C44RaPME-CBRS4HLP.mjs";
|
|
2
|
+
import { l as resolveUserPath, s as isRecord } from "./bundled-dir-U738ay4K-DXK0q_TV.mjs";
|
|
3
|
+
import { l as isPathInside } from "./io-CH2g3vsv-BOGlLlB8.mjs";
|
|
4
|
+
import { Mt as formatErrorMessage, ft as SINGLE_VALUE_FILE_REF_ID, gt as secretRefKey, ht as resolveDefaultSecretProviderAlias, mt as isValidExecSecretRefId, pt as formatExecSecretRefIdValidationMessage } from "./bundled-compat-BpaDaAAu-D7oazKjD.mjs";
|
|
5
|
+
import { m as runExec } from "./runtime-snapshot-C54O1-gI-40cbyi7P.mjs";
|
|
6
|
+
import "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import fs$1 from "node:fs/promises";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import { spawn } from "node:child_process";
|
|
11
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/audit-fs-DNqHeAl9.js
|
|
12
|
+
const INHERIT_FLAGS = new Set([
|
|
13
|
+
"I",
|
|
14
|
+
"OI",
|
|
15
|
+
"CI",
|
|
16
|
+
"IO",
|
|
17
|
+
"NP"
|
|
18
|
+
]);
|
|
19
|
+
const WORLD_PRINCIPALS = new Set([
|
|
20
|
+
"everyone",
|
|
21
|
+
"users",
|
|
22
|
+
"builtin\\users",
|
|
23
|
+
"authenticated users",
|
|
24
|
+
"nt authority\\authenticated users"
|
|
25
|
+
]);
|
|
26
|
+
const TRUSTED_BASE = new Set([
|
|
27
|
+
"nt authority\\system",
|
|
28
|
+
"system",
|
|
29
|
+
"builtin\\administrators",
|
|
30
|
+
"creator owner",
|
|
31
|
+
"autorite nt\\système",
|
|
32
|
+
"nt-autorität\\system",
|
|
33
|
+
"autoridad nt\\system",
|
|
34
|
+
"autoridade nt\\system"
|
|
35
|
+
]);
|
|
36
|
+
const WORLD_SUFFIXES = ["\\users", "\\authenticated users"];
|
|
37
|
+
const TRUSTED_SUFFIXES = [
|
|
38
|
+
"\\administrators",
|
|
39
|
+
"\\system",
|
|
40
|
+
"\\système"
|
|
41
|
+
];
|
|
42
|
+
const SID_RE = /^\*?s-\d+-\d+(-\d+)+$/i;
|
|
43
|
+
const TRUSTED_SIDS = new Set([
|
|
44
|
+
"s-1-5-18",
|
|
45
|
+
"s-1-5-32-544",
|
|
46
|
+
"s-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"
|
|
47
|
+
]);
|
|
48
|
+
const WORLD_SIDS = new Set([
|
|
49
|
+
"s-1-1-0",
|
|
50
|
+
"s-1-5-11",
|
|
51
|
+
"s-1-5-32-545"
|
|
52
|
+
]);
|
|
53
|
+
const STATUS_PREFIXES = [
|
|
54
|
+
"successfully processed",
|
|
55
|
+
"processed",
|
|
56
|
+
"failed processing",
|
|
57
|
+
"no mapping between account names"
|
|
58
|
+
];
|
|
59
|
+
const normalize = (value) => normalizeLowercaseStringOrEmpty(value);
|
|
60
|
+
function normalizeSid(value) {
|
|
61
|
+
const normalized = normalize(value);
|
|
62
|
+
return normalized.startsWith("*") ? normalized.slice(1) : normalized;
|
|
63
|
+
}
|
|
64
|
+
function resolveWindowsUserPrincipal(env) {
|
|
65
|
+
const username = env?.USERNAME?.trim() || os.userInfo().username?.trim();
|
|
66
|
+
if (!username) return null;
|
|
67
|
+
const domain = env?.USERDOMAIN?.trim();
|
|
68
|
+
return domain ? `${domain}\\${username}` : username;
|
|
69
|
+
}
|
|
70
|
+
function buildTrustedPrincipals(env) {
|
|
71
|
+
const trusted = new Set(TRUSTED_BASE);
|
|
72
|
+
const principal = resolveWindowsUserPrincipal(env);
|
|
73
|
+
if (principal) {
|
|
74
|
+
trusted.add(normalize(principal));
|
|
75
|
+
const userOnly = principal.split("\\").at(-1);
|
|
76
|
+
if (userOnly) trusted.add(normalize(userOnly));
|
|
77
|
+
}
|
|
78
|
+
const userSid = normalizeSid(env?.USERSID ?? "");
|
|
79
|
+
if (userSid && SID_RE.test(userSid) && !WORLD_SIDS.has(userSid)) trusted.add(userSid);
|
|
80
|
+
return trusted;
|
|
81
|
+
}
|
|
82
|
+
function classifyPrincipal(principal, trustedPrincipals) {
|
|
83
|
+
const normalized = normalize(principal);
|
|
84
|
+
if (SID_RE.test(normalized)) {
|
|
85
|
+
const sid = normalizeSid(normalized);
|
|
86
|
+
if (WORLD_SIDS.has(sid)) return "world";
|
|
87
|
+
if (TRUSTED_SIDS.has(sid) || trustedPrincipals.has(sid)) return "trusted";
|
|
88
|
+
return "group";
|
|
89
|
+
}
|
|
90
|
+
if (trustedPrincipals.has(normalized) || TRUSTED_SUFFIXES.some((suffix) => normalized.endsWith(suffix))) return "trusted";
|
|
91
|
+
if (WORLD_PRINCIPALS.has(normalized) || WORLD_SUFFIXES.some((suffix) => normalized.endsWith(suffix))) return "world";
|
|
92
|
+
const stripped = normalized.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
93
|
+
if (stripped !== normalized && (TRUSTED_BASE.has(stripped) || TRUSTED_SUFFIXES.some((suffix) => {
|
|
94
|
+
const strippedSuffix = suffix.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
95
|
+
return stripped.endsWith(strippedSuffix);
|
|
96
|
+
}))) return "trusted";
|
|
97
|
+
return "group";
|
|
98
|
+
}
|
|
99
|
+
function rightsFromTokens(tokens) {
|
|
100
|
+
const upper = tokens.join("").toUpperCase();
|
|
101
|
+
const canWrite = upper.includes("F") || upper.includes("M") || upper.includes("W") || upper.includes("D");
|
|
102
|
+
return {
|
|
103
|
+
canRead: upper.includes("F") || upper.includes("M") || upper.includes("R"),
|
|
104
|
+
canWrite
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function isStatusLine(lowerLine) {
|
|
108
|
+
return STATUS_PREFIXES.some((prefix) => lowerLine.startsWith(prefix));
|
|
109
|
+
}
|
|
110
|
+
function stripTargetPrefix(params) {
|
|
111
|
+
if (params.lowerLine.startsWith(params.lowerTarget)) return params.trimmedLine.slice(params.normalizedTarget.length).trim();
|
|
112
|
+
if (params.lowerLine.startsWith(params.quotedLower)) return params.trimmedLine.slice(params.quotedTarget.length).trim();
|
|
113
|
+
return params.trimmedLine;
|
|
114
|
+
}
|
|
115
|
+
function parseAceEntry(entry) {
|
|
116
|
+
if (!entry || !entry.includes("(")) return null;
|
|
117
|
+
const idx = entry.indexOf(":");
|
|
118
|
+
if (idx === -1) return null;
|
|
119
|
+
const principal = entry.slice(0, idx).trim();
|
|
120
|
+
const rawRights = entry.slice(idx + 1).trim();
|
|
121
|
+
const tokens = rawRights.match(/\(([^)]+)\)/g)?.map((token) => token.slice(1, -1).trim()).filter(Boolean) ?? [];
|
|
122
|
+
if (tokens.some((token) => token.toUpperCase() === "DENY")) return null;
|
|
123
|
+
const rights = tokens.filter((token) => !INHERIT_FLAGS.has(token.toUpperCase()));
|
|
124
|
+
if (rights.length === 0) return null;
|
|
125
|
+
const { canRead, canWrite } = rightsFromTokens(rights);
|
|
126
|
+
return {
|
|
127
|
+
principal,
|
|
128
|
+
rights,
|
|
129
|
+
rawRights,
|
|
130
|
+
canRead,
|
|
131
|
+
canWrite
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function parseIcaclsOutput(output, targetPath) {
|
|
135
|
+
const entries = [];
|
|
136
|
+
const normalizedTarget = targetPath.trim();
|
|
137
|
+
const lowerTarget = normalizedTarget.toLowerCase();
|
|
138
|
+
const quotedTarget = `"${normalizedTarget}"`;
|
|
139
|
+
const quotedLower = quotedTarget.toLowerCase();
|
|
140
|
+
for (const rawLine of output.split(/\r?\n/)) {
|
|
141
|
+
const line = rawLine.trimEnd();
|
|
142
|
+
if (!line.trim()) continue;
|
|
143
|
+
const trimmed = line.trim();
|
|
144
|
+
const lower = trimmed.toLowerCase();
|
|
145
|
+
if (isStatusLine(lower)) continue;
|
|
146
|
+
const parsed = parseAceEntry(stripTargetPrefix({
|
|
147
|
+
trimmedLine: trimmed,
|
|
148
|
+
lowerLine: lower,
|
|
149
|
+
normalizedTarget,
|
|
150
|
+
lowerTarget,
|
|
151
|
+
quotedTarget,
|
|
152
|
+
quotedLower
|
|
153
|
+
}));
|
|
154
|
+
if (!parsed) continue;
|
|
155
|
+
entries.push(parsed);
|
|
156
|
+
}
|
|
157
|
+
return entries;
|
|
158
|
+
}
|
|
159
|
+
function summarizeWindowsAcl(entries, env) {
|
|
160
|
+
const trustedPrincipals = buildTrustedPrincipals(env);
|
|
161
|
+
const trusted = [];
|
|
162
|
+
const untrustedWorld = [];
|
|
163
|
+
const untrustedGroup = [];
|
|
164
|
+
for (const entry of entries) {
|
|
165
|
+
const classification = classifyPrincipal(entry.principal, trustedPrincipals);
|
|
166
|
+
if (classification === "trusted") trusted.push(entry);
|
|
167
|
+
else if (classification === "world") untrustedWorld.push(entry);
|
|
168
|
+
else untrustedGroup.push(entry);
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
trusted,
|
|
172
|
+
untrustedWorld,
|
|
173
|
+
untrustedGroup
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async function resolveCurrentUserSid(exec) {
|
|
177
|
+
try {
|
|
178
|
+
const { stdout, stderr } = await exec("whoami", [
|
|
179
|
+
"/user",
|
|
180
|
+
"/fo",
|
|
181
|
+
"csv",
|
|
182
|
+
"/nh"
|
|
183
|
+
]);
|
|
184
|
+
const match = `${stdout}\n${stderr}`.match(/\*?S-\d+-\d+(?:-\d+)+/i);
|
|
185
|
+
return match ? normalizeSid(match[0]) : null;
|
|
186
|
+
} catch (err) {
|
|
187
|
+
console.warn("[windows-acl] resolveCurrentUserSid failed:", String(err));
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function inspectWindowsAcl(targetPath, opts) {
|
|
192
|
+
const exec = opts?.exec ?? runExec;
|
|
193
|
+
try {
|
|
194
|
+
const { stdout, stderr } = await exec("icacls", [targetPath, "/sid"]);
|
|
195
|
+
const entries = parseIcaclsOutput(`${stdout}\n${stderr}`.trim(), targetPath);
|
|
196
|
+
let effectiveEnv = opts?.env;
|
|
197
|
+
let { trusted, untrustedWorld, untrustedGroup } = summarizeWindowsAcl(entries, effectiveEnv);
|
|
198
|
+
if (!effectiveEnv?.USERSID && untrustedGroup.some((entry) => SID_RE.test(normalize(entry.principal)))) {
|
|
199
|
+
const currentUserSid = await resolveCurrentUserSid(exec);
|
|
200
|
+
if (currentUserSid) {
|
|
201
|
+
effectiveEnv = {
|
|
202
|
+
...effectiveEnv,
|
|
203
|
+
USERSID: currentUserSid
|
|
204
|
+
};
|
|
205
|
+
({trusted, untrustedWorld, untrustedGroup} = summarizeWindowsAcl(entries, effectiveEnv));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
ok: true,
|
|
210
|
+
entries,
|
|
211
|
+
trusted,
|
|
212
|
+
untrustedWorld,
|
|
213
|
+
untrustedGroup
|
|
214
|
+
};
|
|
215
|
+
} catch (err) {
|
|
216
|
+
return {
|
|
217
|
+
ok: false,
|
|
218
|
+
entries: [],
|
|
219
|
+
trusted: [],
|
|
220
|
+
untrustedWorld: [],
|
|
221
|
+
untrustedGroup: [],
|
|
222
|
+
error: String(err)
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function formatWindowsAclSummary(summary) {
|
|
227
|
+
if (!summary.ok) return "unknown";
|
|
228
|
+
const untrusted = [...summary.untrustedWorld, ...summary.untrustedGroup];
|
|
229
|
+
if (untrusted.length === 0) return "trusted-only";
|
|
230
|
+
return untrusted.map((entry) => `${entry.principal}:${entry.rawRights}`).join(", ");
|
|
231
|
+
}
|
|
232
|
+
async function safeStat(targetPath) {
|
|
233
|
+
try {
|
|
234
|
+
const lst = await fs$1.lstat(targetPath);
|
|
235
|
+
return {
|
|
236
|
+
ok: true,
|
|
237
|
+
isSymlink: lst.isSymbolicLink(),
|
|
238
|
+
isDir: lst.isDirectory(),
|
|
239
|
+
mode: typeof lst.mode === "number" ? lst.mode : null,
|
|
240
|
+
uid: typeof lst.uid === "number" ? lst.uid : null,
|
|
241
|
+
gid: typeof lst.gid === "number" ? lst.gid : null
|
|
242
|
+
};
|
|
243
|
+
} catch (err) {
|
|
244
|
+
return {
|
|
245
|
+
ok: false,
|
|
246
|
+
isSymlink: false,
|
|
247
|
+
isDir: false,
|
|
248
|
+
mode: null,
|
|
249
|
+
uid: null,
|
|
250
|
+
gid: null,
|
|
251
|
+
error: String(err)
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
async function inspectPathPermissions(targetPath, opts) {
|
|
256
|
+
const st = await safeStat(targetPath);
|
|
257
|
+
if (!st.ok) return {
|
|
258
|
+
ok: false,
|
|
259
|
+
isSymlink: false,
|
|
260
|
+
isDir: false,
|
|
261
|
+
mode: null,
|
|
262
|
+
bits: null,
|
|
263
|
+
source: "unknown",
|
|
264
|
+
worldWritable: false,
|
|
265
|
+
groupWritable: false,
|
|
266
|
+
worldReadable: false,
|
|
267
|
+
groupReadable: false,
|
|
268
|
+
error: st.error
|
|
269
|
+
};
|
|
270
|
+
let effectiveMode = st.mode;
|
|
271
|
+
let effectiveIsDir = st.isDir;
|
|
272
|
+
if (st.isSymlink) try {
|
|
273
|
+
const target = await fs$1.stat(targetPath);
|
|
274
|
+
effectiveMode = typeof target.mode === "number" ? target.mode : st.mode;
|
|
275
|
+
effectiveIsDir = target.isDirectory();
|
|
276
|
+
} catch {}
|
|
277
|
+
const bits = modeBits(effectiveMode);
|
|
278
|
+
if ((opts?.platform ?? process.platform) === "win32") {
|
|
279
|
+
const acl = await inspectWindowsAcl(targetPath, {
|
|
280
|
+
env: opts?.env,
|
|
281
|
+
exec: opts?.exec
|
|
282
|
+
});
|
|
283
|
+
if (!acl.ok) return {
|
|
284
|
+
ok: true,
|
|
285
|
+
isSymlink: st.isSymlink,
|
|
286
|
+
isDir: effectiveIsDir,
|
|
287
|
+
mode: effectiveMode,
|
|
288
|
+
bits,
|
|
289
|
+
source: "unknown",
|
|
290
|
+
worldWritable: false,
|
|
291
|
+
groupWritable: false,
|
|
292
|
+
worldReadable: false,
|
|
293
|
+
groupReadable: false,
|
|
294
|
+
error: acl.error
|
|
295
|
+
};
|
|
296
|
+
return {
|
|
297
|
+
ok: true,
|
|
298
|
+
isSymlink: st.isSymlink,
|
|
299
|
+
isDir: effectiveIsDir,
|
|
300
|
+
mode: effectiveMode,
|
|
301
|
+
bits,
|
|
302
|
+
source: "windows-acl",
|
|
303
|
+
worldWritable: acl.untrustedWorld.some((entry) => entry.canWrite),
|
|
304
|
+
groupWritable: acl.untrustedGroup.some((entry) => entry.canWrite),
|
|
305
|
+
worldReadable: acl.untrustedWorld.some((entry) => entry.canRead),
|
|
306
|
+
groupReadable: acl.untrustedGroup.some((entry) => entry.canRead),
|
|
307
|
+
aclSummary: formatWindowsAclSummary(acl)
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
ok: true,
|
|
312
|
+
isSymlink: st.isSymlink,
|
|
313
|
+
isDir: effectiveIsDir,
|
|
314
|
+
mode: effectiveMode,
|
|
315
|
+
bits,
|
|
316
|
+
source: "posix",
|
|
317
|
+
worldWritable: isWorldWritable(bits),
|
|
318
|
+
groupWritable: isGroupWritable(bits),
|
|
319
|
+
worldReadable: isWorldReadable(bits),
|
|
320
|
+
groupReadable: isGroupReadable(bits)
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function modeBits(mode) {
|
|
324
|
+
if (mode == null) return null;
|
|
325
|
+
return mode & 511;
|
|
326
|
+
}
|
|
327
|
+
function isWorldWritable(bits) {
|
|
328
|
+
if (bits == null) return false;
|
|
329
|
+
return (bits & 2) !== 0;
|
|
330
|
+
}
|
|
331
|
+
function isGroupWritable(bits) {
|
|
332
|
+
if (bits == null) return false;
|
|
333
|
+
return (bits & 16) !== 0;
|
|
334
|
+
}
|
|
335
|
+
function isWorldReadable(bits) {
|
|
336
|
+
if (bits == null) return false;
|
|
337
|
+
return (bits & 4) !== 0;
|
|
338
|
+
}
|
|
339
|
+
function isGroupReadable(bits) {
|
|
340
|
+
if (bits == null) return false;
|
|
341
|
+
return (bits & 32) !== 0;
|
|
342
|
+
}
|
|
343
|
+
//#endregion
|
|
344
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/run-with-concurrency-jYHyKOXI.js
|
|
345
|
+
async function runTasksWithConcurrency(params) {
|
|
346
|
+
const { tasks, limit, onTaskError } = params;
|
|
347
|
+
const errorMode = params.errorMode ?? "continue";
|
|
348
|
+
if (tasks.length === 0) return {
|
|
349
|
+
results: [],
|
|
350
|
+
firstError: void 0,
|
|
351
|
+
hasError: false
|
|
352
|
+
};
|
|
353
|
+
const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));
|
|
354
|
+
const results = Array.from({ length: tasks.length });
|
|
355
|
+
let next = 0;
|
|
356
|
+
let firstError = void 0;
|
|
357
|
+
let hasError = false;
|
|
358
|
+
const workers = Array.from({ length: resolvedLimit }, async () => {
|
|
359
|
+
while (true) {
|
|
360
|
+
if (errorMode === "stop" && hasError) return;
|
|
361
|
+
const index = next;
|
|
362
|
+
next += 1;
|
|
363
|
+
if (index >= tasks.length) return;
|
|
364
|
+
try {
|
|
365
|
+
results[index] = await tasks[index]();
|
|
366
|
+
} catch (error) {
|
|
367
|
+
if (!hasError) {
|
|
368
|
+
firstError = error;
|
|
369
|
+
hasError = true;
|
|
370
|
+
}
|
|
371
|
+
onTaskError?.(error, index);
|
|
372
|
+
if (errorMode === "stop") return;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
await Promise.allSettled(workers);
|
|
377
|
+
return {
|
|
378
|
+
results,
|
|
379
|
+
firstError,
|
|
380
|
+
hasError
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
//#endregion
|
|
384
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/json-pointer-DC9QXazO.js
|
|
385
|
+
function failOrUndefined(params) {
|
|
386
|
+
if (params.onMissing === "throw") throw new Error(params.message);
|
|
387
|
+
}
|
|
388
|
+
function isJsonObject(value) {
|
|
389
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
390
|
+
}
|
|
391
|
+
function decodeJsonPointerToken(token) {
|
|
392
|
+
return token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
393
|
+
}
|
|
394
|
+
function readJsonPointer(root, pointer, options = {}) {
|
|
395
|
+
const onMissing = options.onMissing ?? "throw";
|
|
396
|
+
if (!pointer.startsWith("/")) return failOrUndefined({
|
|
397
|
+
onMissing,
|
|
398
|
+
message: "File-backed secret ids must be absolute JSON pointers (for example: \"/providers/openai/apiKey\")."
|
|
399
|
+
});
|
|
400
|
+
const tokens = pointer.slice(1).split("/").map((token) => decodeJsonPointerToken(token));
|
|
401
|
+
let current = root;
|
|
402
|
+
for (const token of tokens) {
|
|
403
|
+
if (Array.isArray(current)) {
|
|
404
|
+
const index = Number.parseInt(token, 10);
|
|
405
|
+
if (!Number.isFinite(index) || index < 0 || index >= current.length) return failOrUndefined({
|
|
406
|
+
onMissing,
|
|
407
|
+
message: `JSON pointer segment "${token}" is out of bounds.`
|
|
408
|
+
});
|
|
409
|
+
current = current[index];
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
if (!isJsonObject(current)) return failOrUndefined({
|
|
413
|
+
onMissing,
|
|
414
|
+
message: `JSON pointer segment "${token}" does not exist.`
|
|
415
|
+
});
|
|
416
|
+
if (!Object.hasOwn(current, token)) return failOrUndefined({
|
|
417
|
+
onMissing,
|
|
418
|
+
message: `JSON pointer segment "${token}" does not exist.`
|
|
419
|
+
});
|
|
420
|
+
current = current[token];
|
|
421
|
+
}
|
|
422
|
+
return current;
|
|
423
|
+
}
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/shared-BBsAgaUp.js
|
|
426
|
+
function isNonEmptyString(value) {
|
|
427
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
428
|
+
}
|
|
429
|
+
function normalizePositiveInt(value, fallback) {
|
|
430
|
+
if (typeof value === "number" && Number.isFinite(value)) return Math.max(1, Math.floor(value));
|
|
431
|
+
return Math.max(1, Math.floor(fallback));
|
|
432
|
+
}
|
|
433
|
+
//#endregion
|
|
434
|
+
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/resolve-C33B7eeu.js
|
|
435
|
+
const DEFAULT_PROVIDER_CONCURRENCY = 4;
|
|
436
|
+
const DEFAULT_MAX_REFS_PER_PROVIDER = 512;
|
|
437
|
+
const DEFAULT_MAX_BATCH_BYTES = 256 * 1024;
|
|
438
|
+
const DEFAULT_FILE_MAX_BYTES = 1024 * 1024;
|
|
439
|
+
const DEFAULT_FILE_TIMEOUT_MS = 5e3;
|
|
440
|
+
const DEFAULT_EXEC_TIMEOUT_MS = 5e3;
|
|
441
|
+
const DEFAULT_EXEC_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
442
|
+
const WINDOWS_ABS_PATH_PATTERN = /^[A-Za-z]:[\\/]/;
|
|
443
|
+
const WINDOWS_UNC_PATH_PATTERN = /^\\\\[^\\]+\\[^\\]+/;
|
|
444
|
+
var SecretProviderResolutionError = class extends Error {
|
|
445
|
+
constructor(params) {
|
|
446
|
+
super(params.message, params.cause !== void 0 ? { cause: params.cause } : void 0);
|
|
447
|
+
this.scope = "provider";
|
|
448
|
+
this.name = "SecretProviderResolutionError";
|
|
449
|
+
this.source = params.source;
|
|
450
|
+
this.provider = params.provider;
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
var SecretRefResolutionError = class extends Error {
|
|
454
|
+
constructor(params) {
|
|
455
|
+
super(params.message, params.cause !== void 0 ? { cause: params.cause } : void 0);
|
|
456
|
+
this.scope = "ref";
|
|
457
|
+
this.name = "SecretRefResolutionError";
|
|
458
|
+
this.source = params.source;
|
|
459
|
+
this.provider = params.provider;
|
|
460
|
+
this.refId = params.refId;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
function isSecretResolutionError(value) {
|
|
464
|
+
return value instanceof SecretProviderResolutionError || value instanceof SecretRefResolutionError;
|
|
465
|
+
}
|
|
466
|
+
function providerResolutionError(params) {
|
|
467
|
+
return new SecretProviderResolutionError(params);
|
|
468
|
+
}
|
|
469
|
+
function refResolutionError(params) {
|
|
470
|
+
return new SecretRefResolutionError(params);
|
|
471
|
+
}
|
|
472
|
+
function throwUnknownProviderResolutionError(params) {
|
|
473
|
+
if (isSecretResolutionError(params.err)) throw params.err;
|
|
474
|
+
throw providerResolutionError({
|
|
475
|
+
source: params.source,
|
|
476
|
+
provider: params.provider,
|
|
477
|
+
message: formatErrorMessage(params.err),
|
|
478
|
+
cause: params.err
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
async function readFileStatOrThrow(pathname, label) {
|
|
482
|
+
const stat = await safeStat(pathname);
|
|
483
|
+
if (!stat.ok) throw new Error(`${label} is not readable: ${pathname}`);
|
|
484
|
+
if (stat.isDir) throw new Error(`${label} must be a file: ${pathname}`);
|
|
485
|
+
return stat;
|
|
486
|
+
}
|
|
487
|
+
function isAbsolutePathname(value) {
|
|
488
|
+
return path.isAbsolute(value) || WINDOWS_ABS_PATH_PATTERN.test(value) || WINDOWS_UNC_PATH_PATTERN.test(value);
|
|
489
|
+
}
|
|
490
|
+
function resolveResolutionLimits(config) {
|
|
491
|
+
const resolution = config.secrets?.resolution;
|
|
492
|
+
return {
|
|
493
|
+
maxProviderConcurrency: normalizePositiveInt(resolution?.maxProviderConcurrency, DEFAULT_PROVIDER_CONCURRENCY),
|
|
494
|
+
maxRefsPerProvider: normalizePositiveInt(resolution?.maxRefsPerProvider, DEFAULT_MAX_REFS_PER_PROVIDER),
|
|
495
|
+
maxBatchBytes: normalizePositiveInt(resolution?.maxBatchBytes, DEFAULT_MAX_BATCH_BYTES)
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
function toProviderKey(source, provider) {
|
|
499
|
+
return `${source}:${provider}`;
|
|
500
|
+
}
|
|
501
|
+
function resolveConfiguredProvider(ref, config) {
|
|
502
|
+
const providerConfig = config.secrets?.providers?.[ref.provider];
|
|
503
|
+
if (!providerConfig) {
|
|
504
|
+
if (ref.source === "env" && ref.provider === resolveDefaultSecretProviderAlias(config, "env")) return { source: "env" };
|
|
505
|
+
throw providerResolutionError({
|
|
506
|
+
source: ref.source,
|
|
507
|
+
provider: ref.provider,
|
|
508
|
+
message: `Secret provider "${ref.provider}" is not configured (ref: ${ref.source}:${ref.provider}:${ref.id}).`
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
if (providerConfig.source !== ref.source) throw providerResolutionError({
|
|
512
|
+
source: ref.source,
|
|
513
|
+
provider: ref.provider,
|
|
514
|
+
message: `Secret provider "${ref.provider}" has source "${providerConfig.source}" but ref requests "${ref.source}".`
|
|
515
|
+
});
|
|
516
|
+
return providerConfig;
|
|
517
|
+
}
|
|
518
|
+
async function assertSecurePath(params) {
|
|
519
|
+
if (!isAbsolutePathname(params.targetPath)) throw new Error(`${params.label} must be an absolute path.`);
|
|
520
|
+
let effectivePath = params.targetPath;
|
|
521
|
+
let stat = await readFileStatOrThrow(effectivePath, params.label);
|
|
522
|
+
if (stat.isSymlink) {
|
|
523
|
+
if (!params.allowSymlinkPath) throw new Error(`${params.label} must not be a symlink: ${effectivePath}`);
|
|
524
|
+
try {
|
|
525
|
+
effectivePath = await fs$1.realpath(effectivePath);
|
|
526
|
+
} catch {
|
|
527
|
+
throw new Error(`${params.label} symlink target is not readable: ${params.targetPath}`);
|
|
528
|
+
}
|
|
529
|
+
if (!isAbsolutePathname(effectivePath)) throw new Error(`${params.label} resolved symlink target must be an absolute path.`);
|
|
530
|
+
stat = await readFileStatOrThrow(effectivePath, params.label);
|
|
531
|
+
if (stat.isSymlink) throw new Error(`${params.label} symlink target must not be a symlink: ${effectivePath}`);
|
|
532
|
+
}
|
|
533
|
+
if (params.trustedDirs && params.trustedDirs.length > 0) {
|
|
534
|
+
if (!params.trustedDirs.map((entry) => resolveUserPath(entry)).some((dir) => isPathInside(dir, effectivePath))) throw new Error(`${params.label} is outside trustedDirs: ${effectivePath}`);
|
|
535
|
+
}
|
|
536
|
+
if (params.allowInsecurePath) return effectivePath;
|
|
537
|
+
const perms = await inspectPathPermissions(effectivePath);
|
|
538
|
+
if (!perms.ok) throw new Error(`${params.label} permissions could not be verified: ${effectivePath}`);
|
|
539
|
+
const writableByOthers = perms.worldWritable || perms.groupWritable;
|
|
540
|
+
const readableByOthers = perms.worldReadable || perms.groupReadable;
|
|
541
|
+
if (writableByOthers || !params.allowReadableByOthers && readableByOthers) throw new Error(`${params.label} permissions are too open: ${effectivePath}`);
|
|
542
|
+
if (process.platform === "win32" && perms.source === "unknown") throw new Error(`${params.label} ACL verification unavailable on Windows for ${effectivePath}. Set allowInsecurePath=true for this provider to bypass this check when the path is trusted.`);
|
|
543
|
+
if (process.platform !== "win32" && typeof process.getuid === "function" && stat.uid != null) {
|
|
544
|
+
const uid = process.getuid();
|
|
545
|
+
if (stat.uid !== uid) throw new Error(`${params.label} must be owned by the current user (uid=${uid}): ${effectivePath}`);
|
|
546
|
+
}
|
|
547
|
+
return effectivePath;
|
|
548
|
+
}
|
|
549
|
+
async function readFileProviderPayload(params) {
|
|
550
|
+
const cacheKey = params.providerName;
|
|
551
|
+
const cache = params.cache;
|
|
552
|
+
const cachedFilePayload = cache?.filePayloadByProvider?.get(cacheKey);
|
|
553
|
+
if (cachedFilePayload) return await cachedFilePayload;
|
|
554
|
+
const filePath = resolveUserPath(params.providerConfig.path);
|
|
555
|
+
const readPromise = (async () => {
|
|
556
|
+
const secureFilePath = await assertSecurePath({
|
|
557
|
+
targetPath: filePath,
|
|
558
|
+
label: `secrets.providers.${params.providerName}.path`
|
|
559
|
+
});
|
|
560
|
+
const timeoutMs = normalizePositiveInt(params.providerConfig.timeoutMs, DEFAULT_FILE_TIMEOUT_MS);
|
|
561
|
+
const maxBytes = normalizePositiveInt(params.providerConfig.maxBytes, DEFAULT_FILE_MAX_BYTES);
|
|
562
|
+
const abortController = new AbortController();
|
|
563
|
+
const timeoutErrorMessage = `File provider "${params.providerName}" timed out after ${timeoutMs}ms.`;
|
|
564
|
+
let timeoutHandle = null;
|
|
565
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
566
|
+
timeoutHandle = setTimeout(() => {
|
|
567
|
+
abortController.abort();
|
|
568
|
+
reject(new Error(timeoutErrorMessage));
|
|
569
|
+
}, timeoutMs);
|
|
570
|
+
});
|
|
571
|
+
try {
|
|
572
|
+
const payload = await Promise.race([fs$1.readFile(secureFilePath, { signal: abortController.signal }), timeoutPromise]);
|
|
573
|
+
if (payload.byteLength > maxBytes) throw new Error(`File provider "${params.providerName}" exceeded maxBytes (${maxBytes}).`);
|
|
574
|
+
const text = payload.toString("utf8");
|
|
575
|
+
if (params.providerConfig.mode === "singleValue") return text.replace(/\r?\n$/, "");
|
|
576
|
+
const parsed = JSON.parse(text);
|
|
577
|
+
if (!isRecord(parsed)) throw new Error(`File provider "${params.providerName}" payload is not a JSON object.`);
|
|
578
|
+
return parsed;
|
|
579
|
+
} catch (error) {
|
|
580
|
+
if (error instanceof Error && error.name === "AbortError") throw new Error(timeoutErrorMessage, { cause: error });
|
|
581
|
+
throw error;
|
|
582
|
+
} finally {
|
|
583
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
584
|
+
}
|
|
585
|
+
})();
|
|
586
|
+
if (cache) {
|
|
587
|
+
cache.filePayloadByProvider ??= /* @__PURE__ */ new Map();
|
|
588
|
+
cache.filePayloadByProvider.set(cacheKey, readPromise);
|
|
589
|
+
}
|
|
590
|
+
return await readPromise;
|
|
591
|
+
}
|
|
592
|
+
async function resolveEnvRefs(params) {
|
|
593
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
594
|
+
const allowlist = params.providerConfig.allowlist ? new Set(params.providerConfig.allowlist) : null;
|
|
595
|
+
for (const ref of params.refs) {
|
|
596
|
+
if (allowlist && !allowlist.has(ref.id)) throw refResolutionError({
|
|
597
|
+
source: "env",
|
|
598
|
+
provider: params.providerName,
|
|
599
|
+
refId: ref.id,
|
|
600
|
+
message: `Environment variable "${ref.id}" is not allowlisted in secrets.providers.${params.providerName}.allowlist.`
|
|
601
|
+
});
|
|
602
|
+
const envValue = params.env[ref.id];
|
|
603
|
+
if (!isNonEmptyString(envValue)) throw refResolutionError({
|
|
604
|
+
source: "env",
|
|
605
|
+
provider: params.providerName,
|
|
606
|
+
refId: ref.id,
|
|
607
|
+
message: `Environment variable "${ref.id}" is missing or empty.`
|
|
608
|
+
});
|
|
609
|
+
resolved.set(ref.id, envValue);
|
|
610
|
+
}
|
|
611
|
+
return resolved;
|
|
612
|
+
}
|
|
613
|
+
async function resolveFileRefs(params) {
|
|
614
|
+
let payload;
|
|
615
|
+
try {
|
|
616
|
+
payload = await readFileProviderPayload({
|
|
617
|
+
providerName: params.providerName,
|
|
618
|
+
providerConfig: params.providerConfig,
|
|
619
|
+
cache: params.cache
|
|
620
|
+
});
|
|
621
|
+
} catch (err) {
|
|
622
|
+
throwUnknownProviderResolutionError({
|
|
623
|
+
source: "file",
|
|
624
|
+
provider: params.providerName,
|
|
625
|
+
err
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
const mode = params.providerConfig.mode ?? "json";
|
|
629
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
630
|
+
if (mode === "singleValue") {
|
|
631
|
+
for (const ref of params.refs) {
|
|
632
|
+
if (ref.id !== "value") throw refResolutionError({
|
|
633
|
+
source: "file",
|
|
634
|
+
provider: params.providerName,
|
|
635
|
+
refId: ref.id,
|
|
636
|
+
message: `singleValue file provider "${params.providerName}" expects ref id "${SINGLE_VALUE_FILE_REF_ID}".`
|
|
637
|
+
});
|
|
638
|
+
resolved.set(ref.id, payload);
|
|
639
|
+
}
|
|
640
|
+
return resolved;
|
|
641
|
+
}
|
|
642
|
+
for (const ref of params.refs) try {
|
|
643
|
+
resolved.set(ref.id, readJsonPointer(payload, ref.id, { onMissing: "throw" }));
|
|
644
|
+
} catch (err) {
|
|
645
|
+
throw refResolutionError({
|
|
646
|
+
source: "file",
|
|
647
|
+
provider: params.providerName,
|
|
648
|
+
refId: ref.id,
|
|
649
|
+
message: formatErrorMessage(err),
|
|
650
|
+
cause: err
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
return resolved;
|
|
654
|
+
}
|
|
655
|
+
function isIgnorableStdinWriteError(error) {
|
|
656
|
+
if (typeof error !== "object" || error === null || !("code" in error)) return false;
|
|
657
|
+
const code = String(error.code);
|
|
658
|
+
return code === "EPIPE" || code === "ERR_STREAM_DESTROYED";
|
|
659
|
+
}
|
|
660
|
+
async function runExecResolver(params) {
|
|
661
|
+
return await new Promise((resolve, reject) => {
|
|
662
|
+
const child = spawn(params.command, params.args, {
|
|
663
|
+
cwd: params.cwd,
|
|
664
|
+
env: params.env,
|
|
665
|
+
stdio: [
|
|
666
|
+
"pipe",
|
|
667
|
+
"pipe",
|
|
668
|
+
"pipe"
|
|
669
|
+
],
|
|
670
|
+
shell: false,
|
|
671
|
+
windowsHide: true
|
|
672
|
+
});
|
|
673
|
+
let settled = false;
|
|
674
|
+
let stdout = "";
|
|
675
|
+
let stderr = "";
|
|
676
|
+
let timedOut = false;
|
|
677
|
+
let noOutputTimedOut = false;
|
|
678
|
+
let outputBytes = 0;
|
|
679
|
+
let noOutputTimer = null;
|
|
680
|
+
const timeoutTimer = setTimeout(() => {
|
|
681
|
+
timedOut = true;
|
|
682
|
+
child.kill("SIGKILL");
|
|
683
|
+
}, params.timeoutMs);
|
|
684
|
+
const clearTimers = () => {
|
|
685
|
+
clearTimeout(timeoutTimer);
|
|
686
|
+
if (noOutputTimer) {
|
|
687
|
+
clearTimeout(noOutputTimer);
|
|
688
|
+
noOutputTimer = null;
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
const armNoOutputTimer = () => {
|
|
692
|
+
if (noOutputTimer) clearTimeout(noOutputTimer);
|
|
693
|
+
noOutputTimer = setTimeout(() => {
|
|
694
|
+
noOutputTimedOut = true;
|
|
695
|
+
child.kill("SIGKILL");
|
|
696
|
+
}, params.noOutputTimeoutMs);
|
|
697
|
+
};
|
|
698
|
+
const append = (chunk, target) => {
|
|
699
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
700
|
+
outputBytes += Buffer.byteLength(text, "utf8");
|
|
701
|
+
if (outputBytes > params.maxOutputBytes) {
|
|
702
|
+
child.kill("SIGKILL");
|
|
703
|
+
if (!settled) {
|
|
704
|
+
settled = true;
|
|
705
|
+
clearTimers();
|
|
706
|
+
reject(/* @__PURE__ */ new Error(`Exec provider output exceeded maxOutputBytes (${params.maxOutputBytes}).`));
|
|
707
|
+
}
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
if (target === "stdout") stdout += text;
|
|
711
|
+
else stderr += text;
|
|
712
|
+
armNoOutputTimer();
|
|
713
|
+
};
|
|
714
|
+
armNoOutputTimer();
|
|
715
|
+
child.on("error", (error) => {
|
|
716
|
+
if (settled) return;
|
|
717
|
+
settled = true;
|
|
718
|
+
clearTimers();
|
|
719
|
+
reject(error);
|
|
720
|
+
});
|
|
721
|
+
child.stdout?.on("data", (chunk) => append(chunk, "stdout"));
|
|
722
|
+
child.stderr?.on("data", (chunk) => append(chunk, "stderr"));
|
|
723
|
+
child.on("close", (code, signal) => {
|
|
724
|
+
if (settled) return;
|
|
725
|
+
settled = true;
|
|
726
|
+
clearTimers();
|
|
727
|
+
resolve({
|
|
728
|
+
stdout,
|
|
729
|
+
stderr,
|
|
730
|
+
code,
|
|
731
|
+
signal,
|
|
732
|
+
termination: noOutputTimedOut ? "no-output-timeout" : timedOut ? "timeout" : "exit"
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
const handleStdinError = (error) => {
|
|
736
|
+
if (isIgnorableStdinWriteError(error) || settled) return;
|
|
737
|
+
settled = true;
|
|
738
|
+
clearTimers();
|
|
739
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
740
|
+
};
|
|
741
|
+
child.stdin?.on("error", handleStdinError);
|
|
742
|
+
try {
|
|
743
|
+
child.stdin?.end(params.input);
|
|
744
|
+
} catch (error) {
|
|
745
|
+
handleStdinError(error);
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
function parseExecValues(params) {
|
|
750
|
+
const trimmed = params.stdout.trim();
|
|
751
|
+
if (!trimmed) throw providerResolutionError({
|
|
752
|
+
source: "exec",
|
|
753
|
+
provider: params.providerName,
|
|
754
|
+
message: `Exec provider "${params.providerName}" returned empty stdout.`
|
|
755
|
+
});
|
|
756
|
+
let parsed;
|
|
757
|
+
if (!params.jsonOnly && params.ids.length === 1) try {
|
|
758
|
+
parsed = JSON.parse(trimmed);
|
|
759
|
+
} catch {
|
|
760
|
+
return { [params.ids[0]]: trimmed };
|
|
761
|
+
}
|
|
762
|
+
else try {
|
|
763
|
+
parsed = JSON.parse(trimmed);
|
|
764
|
+
} catch {
|
|
765
|
+
throw providerResolutionError({
|
|
766
|
+
source: "exec",
|
|
767
|
+
provider: params.providerName,
|
|
768
|
+
message: `Exec provider "${params.providerName}" returned invalid JSON.`
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
if (!isRecord(parsed)) {
|
|
772
|
+
if (!params.jsonOnly && params.ids.length === 1 && typeof parsed === "string") return { [params.ids[0]]: parsed };
|
|
773
|
+
throw providerResolutionError({
|
|
774
|
+
source: "exec",
|
|
775
|
+
provider: params.providerName,
|
|
776
|
+
message: `Exec provider "${params.providerName}" response must be an object.`
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
if (parsed.protocolVersion !== 1) throw providerResolutionError({
|
|
780
|
+
source: "exec",
|
|
781
|
+
provider: params.providerName,
|
|
782
|
+
message: `Exec provider "${params.providerName}" protocolVersion must be 1.`
|
|
783
|
+
});
|
|
784
|
+
const responseValues = parsed.values;
|
|
785
|
+
if (!isRecord(responseValues)) throw providerResolutionError({
|
|
786
|
+
source: "exec",
|
|
787
|
+
provider: params.providerName,
|
|
788
|
+
message: `Exec provider "${params.providerName}" response missing "values".`
|
|
789
|
+
});
|
|
790
|
+
const responseErrors = isRecord(parsed.errors) ? parsed.errors : null;
|
|
791
|
+
const out = {};
|
|
792
|
+
for (const id of params.ids) {
|
|
793
|
+
if (responseErrors && id in responseErrors) {
|
|
794
|
+
const entry = responseErrors[id];
|
|
795
|
+
if (isRecord(entry) && typeof entry.message === "string" && entry.message.trim()) throw refResolutionError({
|
|
796
|
+
source: "exec",
|
|
797
|
+
provider: params.providerName,
|
|
798
|
+
refId: id,
|
|
799
|
+
message: `Exec provider "${params.providerName}" failed for id "${id}" (${entry.message.trim()}).`
|
|
800
|
+
});
|
|
801
|
+
throw refResolutionError({
|
|
802
|
+
source: "exec",
|
|
803
|
+
provider: params.providerName,
|
|
804
|
+
refId: id,
|
|
805
|
+
message: `Exec provider "${params.providerName}" failed for id "${id}".`
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
if (!(id in responseValues)) throw refResolutionError({
|
|
809
|
+
source: "exec",
|
|
810
|
+
provider: params.providerName,
|
|
811
|
+
refId: id,
|
|
812
|
+
message: `Exec provider "${params.providerName}" response missing id "${id}".`
|
|
813
|
+
});
|
|
814
|
+
out[id] = responseValues[id];
|
|
815
|
+
}
|
|
816
|
+
return out;
|
|
817
|
+
}
|
|
818
|
+
async function resolveExecRefs(params) {
|
|
819
|
+
const ids = [...new Set(params.refs.map((ref) => ref.id))];
|
|
820
|
+
if (ids.length > params.limits.maxRefsPerProvider) throw providerResolutionError({
|
|
821
|
+
source: "exec",
|
|
822
|
+
provider: params.providerName,
|
|
823
|
+
message: `Exec provider "${params.providerName}" exceeded maxRefsPerProvider (${params.limits.maxRefsPerProvider}).`
|
|
824
|
+
});
|
|
825
|
+
const commandPath = resolveUserPath(params.providerConfig.command);
|
|
826
|
+
let secureCommandPath;
|
|
827
|
+
try {
|
|
828
|
+
secureCommandPath = await assertSecurePath({
|
|
829
|
+
targetPath: commandPath,
|
|
830
|
+
label: `secrets.providers.${params.providerName}.command`,
|
|
831
|
+
trustedDirs: params.providerConfig.trustedDirs,
|
|
832
|
+
allowInsecurePath: params.providerConfig.allowInsecurePath,
|
|
833
|
+
allowReadableByOthers: true,
|
|
834
|
+
allowSymlinkPath: params.providerConfig.allowSymlinkCommand
|
|
835
|
+
});
|
|
836
|
+
} catch (err) {
|
|
837
|
+
throwUnknownProviderResolutionError({
|
|
838
|
+
source: "exec",
|
|
839
|
+
provider: params.providerName,
|
|
840
|
+
err
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
const requestPayload = {
|
|
844
|
+
protocolVersion: 1,
|
|
845
|
+
provider: params.providerName,
|
|
846
|
+
ids
|
|
847
|
+
};
|
|
848
|
+
const input = JSON.stringify(requestPayload);
|
|
849
|
+
if (Buffer.byteLength(input, "utf8") > params.limits.maxBatchBytes) throw providerResolutionError({
|
|
850
|
+
source: "exec",
|
|
851
|
+
provider: params.providerName,
|
|
852
|
+
message: `Exec provider "${params.providerName}" request exceeded maxBatchBytes (${params.limits.maxBatchBytes}).`
|
|
853
|
+
});
|
|
854
|
+
const childEnv = {};
|
|
855
|
+
for (const key of params.providerConfig.passEnv ?? []) {
|
|
856
|
+
const value = params.env[key];
|
|
857
|
+
if (value !== void 0) childEnv[key] = value;
|
|
858
|
+
}
|
|
859
|
+
for (const [key, value] of Object.entries(params.providerConfig.env ?? {})) childEnv[key] = value;
|
|
860
|
+
const timeoutMs = normalizePositiveInt(params.providerConfig.timeoutMs, DEFAULT_EXEC_TIMEOUT_MS);
|
|
861
|
+
const noOutputTimeoutMs = normalizePositiveInt(params.providerConfig.noOutputTimeoutMs, timeoutMs);
|
|
862
|
+
const maxOutputBytes = normalizePositiveInt(params.providerConfig.maxOutputBytes, DEFAULT_EXEC_MAX_OUTPUT_BYTES);
|
|
863
|
+
const jsonOnly = params.providerConfig.jsonOnly ?? true;
|
|
864
|
+
let result;
|
|
865
|
+
try {
|
|
866
|
+
result = await runExecResolver({
|
|
867
|
+
command: secureCommandPath,
|
|
868
|
+
args: params.providerConfig.args ?? [],
|
|
869
|
+
cwd: path.dirname(secureCommandPath),
|
|
870
|
+
env: childEnv,
|
|
871
|
+
input,
|
|
872
|
+
timeoutMs,
|
|
873
|
+
noOutputTimeoutMs,
|
|
874
|
+
maxOutputBytes
|
|
875
|
+
});
|
|
876
|
+
} catch (err) {
|
|
877
|
+
throwUnknownProviderResolutionError({
|
|
878
|
+
source: "exec",
|
|
879
|
+
provider: params.providerName,
|
|
880
|
+
err
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
if (result.termination === "timeout") throw providerResolutionError({
|
|
884
|
+
source: "exec",
|
|
885
|
+
provider: params.providerName,
|
|
886
|
+
message: `Exec provider "${params.providerName}" timed out after ${timeoutMs}ms.`
|
|
887
|
+
});
|
|
888
|
+
if (result.termination === "no-output-timeout") throw providerResolutionError({
|
|
889
|
+
source: "exec",
|
|
890
|
+
provider: params.providerName,
|
|
891
|
+
message: `Exec provider "${params.providerName}" produced no output for ${noOutputTimeoutMs}ms.`
|
|
892
|
+
});
|
|
893
|
+
if (result.code !== 0) throw providerResolutionError({
|
|
894
|
+
source: "exec",
|
|
895
|
+
provider: params.providerName,
|
|
896
|
+
message: `Exec provider "${params.providerName}" exited with code ${String(result.code)}.`
|
|
897
|
+
});
|
|
898
|
+
let values;
|
|
899
|
+
try {
|
|
900
|
+
values = parseExecValues({
|
|
901
|
+
providerName: params.providerName,
|
|
902
|
+
ids,
|
|
903
|
+
stdout: result.stdout,
|
|
904
|
+
jsonOnly
|
|
905
|
+
});
|
|
906
|
+
} catch (err) {
|
|
907
|
+
throwUnknownProviderResolutionError({
|
|
908
|
+
source: "exec",
|
|
909
|
+
provider: params.providerName,
|
|
910
|
+
err
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
914
|
+
for (const id of ids) resolved.set(id, values[id]);
|
|
915
|
+
return resolved;
|
|
916
|
+
}
|
|
917
|
+
async function resolveProviderRefs(params) {
|
|
918
|
+
try {
|
|
919
|
+
if (params.providerConfig.source === "env") return await resolveEnvRefs({
|
|
920
|
+
refs: params.refs,
|
|
921
|
+
providerName: params.providerName,
|
|
922
|
+
providerConfig: params.providerConfig,
|
|
923
|
+
env: params.options.env ?? process.env
|
|
924
|
+
});
|
|
925
|
+
if (params.providerConfig.source === "file") return await resolveFileRefs({
|
|
926
|
+
refs: params.refs,
|
|
927
|
+
providerName: params.providerName,
|
|
928
|
+
providerConfig: params.providerConfig,
|
|
929
|
+
cache: params.options.cache
|
|
930
|
+
});
|
|
931
|
+
if (params.providerConfig.source === "exec") return await resolveExecRefs({
|
|
932
|
+
refs: params.refs,
|
|
933
|
+
providerName: params.providerName,
|
|
934
|
+
providerConfig: params.providerConfig,
|
|
935
|
+
env: params.options.env ?? process.env,
|
|
936
|
+
limits: params.limits
|
|
937
|
+
});
|
|
938
|
+
throw providerResolutionError({
|
|
939
|
+
source: params.source,
|
|
940
|
+
provider: params.providerName,
|
|
941
|
+
message: `Unsupported secret provider source "${String(params.providerConfig.source)}".`
|
|
942
|
+
});
|
|
943
|
+
} catch (err) {
|
|
944
|
+
return throwUnknownProviderResolutionError({
|
|
945
|
+
source: params.source,
|
|
946
|
+
provider: params.providerName,
|
|
947
|
+
err
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
async function resolveSecretRefValues(refs, options) {
|
|
952
|
+
if (refs.length === 0) return /* @__PURE__ */ new Map();
|
|
953
|
+
const limits = resolveResolutionLimits(options.config);
|
|
954
|
+
const uniqueRefs = /* @__PURE__ */ new Map();
|
|
955
|
+
for (const ref of refs) {
|
|
956
|
+
const id = ref.id.trim();
|
|
957
|
+
if (!id) throw new Error("Secret reference id is empty.");
|
|
958
|
+
if (ref.source === "exec" && !isValidExecSecretRefId(id)) throw new Error(`${formatExecSecretRefIdValidationMessage()} (ref: ${ref.source}:${ref.provider}:${id}).`);
|
|
959
|
+
uniqueRefs.set(secretRefKey(ref), {
|
|
960
|
+
...ref,
|
|
961
|
+
id
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
965
|
+
for (const ref of uniqueRefs.values()) {
|
|
966
|
+
const key = toProviderKey(ref.source, ref.provider);
|
|
967
|
+
const existing = grouped.get(key);
|
|
968
|
+
if (existing) {
|
|
969
|
+
existing.refs.push(ref);
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
grouped.set(key, {
|
|
973
|
+
source: ref.source,
|
|
974
|
+
providerName: ref.provider,
|
|
975
|
+
refs: [ref]
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
const taskResults = await runTasksWithConcurrency({
|
|
979
|
+
tasks: [...grouped.values()].map((group) => async () => {
|
|
980
|
+
if (group.refs.length > limits.maxRefsPerProvider) throw providerResolutionError({
|
|
981
|
+
source: group.source,
|
|
982
|
+
provider: group.providerName,
|
|
983
|
+
message: `Secret provider "${group.providerName}" exceeded maxRefsPerProvider (${limits.maxRefsPerProvider}).`
|
|
984
|
+
});
|
|
985
|
+
const providerConfig = resolveConfiguredProvider(group.refs[0], options.config);
|
|
986
|
+
return {
|
|
987
|
+
group,
|
|
988
|
+
values: await resolveProviderRefs({
|
|
989
|
+
refs: group.refs,
|
|
990
|
+
source: group.source,
|
|
991
|
+
providerName: group.providerName,
|
|
992
|
+
providerConfig,
|
|
993
|
+
options,
|
|
994
|
+
limits
|
|
995
|
+
})
|
|
996
|
+
};
|
|
997
|
+
}),
|
|
998
|
+
limit: limits.maxProviderConcurrency,
|
|
999
|
+
errorMode: "stop"
|
|
1000
|
+
});
|
|
1001
|
+
if (taskResults.hasError) throw taskResults.firstError;
|
|
1002
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
1003
|
+
for (const result of taskResults.results) for (const ref of result.group.refs) {
|
|
1004
|
+
if (!result.values.has(ref.id)) throw refResolutionError({
|
|
1005
|
+
source: result.group.source,
|
|
1006
|
+
provider: result.group.providerName,
|
|
1007
|
+
refId: ref.id,
|
|
1008
|
+
message: `Secret provider "${result.group.providerName}" did not return id "${ref.id}".`
|
|
1009
|
+
});
|
|
1010
|
+
resolved.set(secretRefKey(ref), result.values.get(ref.id));
|
|
1011
|
+
}
|
|
1012
|
+
return resolved;
|
|
1013
|
+
}
|
|
1014
|
+
async function resolveSecretRefValue(ref, options) {
|
|
1015
|
+
const cache = options.cache;
|
|
1016
|
+
const key = secretRefKey(ref);
|
|
1017
|
+
const cachedResolvedValue = cache?.resolvedByRefKey?.get(key);
|
|
1018
|
+
if (cachedResolvedValue) return await cachedResolvedValue;
|
|
1019
|
+
const promise = (async () => {
|
|
1020
|
+
const resolved = await resolveSecretRefValues([ref], options);
|
|
1021
|
+
if (!resolved.has(key)) throw refResolutionError({
|
|
1022
|
+
source: ref.source,
|
|
1023
|
+
provider: ref.provider,
|
|
1024
|
+
refId: ref.id,
|
|
1025
|
+
message: `Secret reference "${key}" resolved to no value.`
|
|
1026
|
+
});
|
|
1027
|
+
return resolved.get(key);
|
|
1028
|
+
})();
|
|
1029
|
+
if (cache) {
|
|
1030
|
+
cache.resolvedByRefKey ??= /* @__PURE__ */ new Map();
|
|
1031
|
+
cache.resolvedByRefKey.set(key, promise);
|
|
1032
|
+
}
|
|
1033
|
+
return await promise;
|
|
1034
|
+
}
|
|
1035
|
+
async function resolveSecretRefString(ref, options) {
|
|
1036
|
+
const resolved = await resolveSecretRefValue(ref, options);
|
|
1037
|
+
if (!isNonEmptyString(resolved)) throw new Error(`Secret reference "${ref.source}:${ref.provider}:${ref.id}" resolved to a non-string or empty value.`);
|
|
1038
|
+
return resolved;
|
|
1039
|
+
}
|
|
1040
|
+
//#endregion
|
|
1041
|
+
export { resolveSecretRefString as t };
|