kly 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/config-builder-D5EtwOB3.mjs +3 -0
- package/dist/bin/kly.mjs +84 -24
- package/dist/bin/kly.mjs.map +1 -1
- package/dist/bin/launcher-Ex3ynZdE.mjs +3 -0
- package/dist/bin/permissions-C_WgoA3t.mjs +3 -0
- package/dist/bin/permissions-extractor-BfUPS0Tr.mjs +29 -0
- package/dist/bin/permissions-extractor-BfUPS0Tr.mjs.map +1 -0
- package/dist/define-app.d.mts.map +1 -1
- package/dist/define-app.mjs +8 -1
- package/dist/define-app.mjs.map +1 -1
- package/dist/sandbox/bundled-executor.mjs +5 -2
- package/dist/sandbox/bundled-executor.mjs.map +1 -1
- package/dist/sandbox/sandboxed-context.mjs.map +1 -1
- package/dist/types.d.mts +30 -1
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/bin/launcher-vTpgdO9n.mjs +0 -3
- package/dist/bin/permissions-2r_7ZqaH.mjs +0 -3
package/dist/bin/kly.mjs
CHANGED
|
@@ -950,9 +950,10 @@ function createResourceProvider(options) {
|
|
|
950
950
|
* 4. Returns execution result
|
|
951
951
|
*/
|
|
952
952
|
async function launchSandbox(options) {
|
|
953
|
-
const { scriptPath, args: args$1, appId, sandboxConfig, allowApiKey } = options;
|
|
953
|
+
const { scriptPath, args: args$1, appId, invokeDir, sandboxConfig, allowApiKey } = options;
|
|
954
954
|
await SandboxManager.initialize(sandboxConfig);
|
|
955
955
|
const absoluteScriptPath = resolve(process.cwd(), scriptPath);
|
|
956
|
+
const _scriptDir = absoluteScriptPath.substring(0, absoluteScriptPath.lastIndexOf("/"));
|
|
956
957
|
const executorPath = resolve(__dirname, "../sandbox/bundled-executor.mjs");
|
|
957
958
|
if (!SandboxManager.isSandboxingEnabled()) {
|
|
958
959
|
console.warn("⚠️ Sandboxing is not supported on this platform.");
|
|
@@ -973,6 +974,7 @@ async function launchSandbox(options) {
|
|
|
973
974
|
"inherit",
|
|
974
975
|
"ipc"
|
|
975
976
|
],
|
|
977
|
+
cwd: _scriptDir,
|
|
976
978
|
env: {
|
|
977
979
|
...process.env,
|
|
978
980
|
KLY_SANDBOX_MODE: "true"
|
|
@@ -994,6 +996,7 @@ async function launchSandbox(options) {
|
|
|
994
996
|
scriptPath: absoluteScriptPath,
|
|
995
997
|
args: args$1,
|
|
996
998
|
appId,
|
|
999
|
+
invokeDir,
|
|
997
1000
|
permissions: {
|
|
998
1001
|
allowApiKey,
|
|
999
1002
|
sandboxConfig
|
|
@@ -1843,22 +1846,42 @@ async function clearAllPermissionsAction() {
|
|
|
1843
1846
|
*/
|
|
1844
1847
|
const PROTECTED_PATHS = {
|
|
1845
1848
|
alwaysDenyWrite: [
|
|
1846
|
-
join(homedir(), ".kly"),
|
|
1849
|
+
join(homedir(), ".kly/config"),
|
|
1850
|
+
join(homedir(), ".kly/permissions.json"),
|
|
1851
|
+
join(homedir(), ".kly/kly.sum"),
|
|
1847
1852
|
join(homedir(), ".ssh"),
|
|
1848
1853
|
join(homedir(), ".aws"),
|
|
1849
1854
|
join(homedir(), ".gnupg")
|
|
1850
1855
|
],
|
|
1851
|
-
alwaysDenyRead: [join(homedir(), ".kly")]
|
|
1856
|
+
alwaysDenyRead: [join(homedir(), ".kly/config"), join(homedir(), ".kly/permissions.json")]
|
|
1852
1857
|
};
|
|
1853
1858
|
/**
|
|
1859
|
+
* Resolve filesystem path with special marker support
|
|
1860
|
+
*
|
|
1861
|
+
* Special markers:
|
|
1862
|
+
* - "*": User's home directory (allows access to all non-sensitive files)
|
|
1863
|
+
* - Absolute paths: Used as-is
|
|
1864
|
+
*
|
|
1865
|
+
* @param path - Path to resolve (may contain special markers)
|
|
1866
|
+
* @returns Resolved absolute path, or undefined if path is undefined
|
|
1867
|
+
*/
|
|
1868
|
+
function resolveFilesystemPath(path) {
|
|
1869
|
+
if (!path) return void 0;
|
|
1870
|
+
if (path === "*") return homedir();
|
|
1871
|
+
return path;
|
|
1872
|
+
}
|
|
1873
|
+
/**
|
|
1854
1874
|
* Build a complete SandboxRuntimeConfig from declared app permissions
|
|
1855
1875
|
*
|
|
1856
1876
|
* This merges:
|
|
1857
1877
|
* 1. Default safe configuration
|
|
1858
1878
|
* 2. Automatic LLM domains (if apiKeys: true)
|
|
1859
|
-
* 3. User-declared sandbox config
|
|
1879
|
+
* 3. User-declared sandbox config (with special marker support)
|
|
1860
1880
|
* 4. Mandatory protections (always applied)
|
|
1861
1881
|
*
|
|
1882
|
+
* Special markers in filesystem paths:
|
|
1883
|
+
* - "*": Allows access to all files in user's home directory (except sensitive paths)
|
|
1884
|
+
*
|
|
1862
1885
|
* @param permissions - Declared app permissions
|
|
1863
1886
|
* @returns Complete sandbox configuration ready for SandboxManager
|
|
1864
1887
|
*/
|
|
@@ -1870,10 +1893,16 @@ function buildSandboxConfig(permissions) {
|
|
|
1870
1893
|
if (permissions?.apiKeys) allowedDomains = [...LLM_API_DOMAINS];
|
|
1871
1894
|
if (permissions?.sandbox) {
|
|
1872
1895
|
const userSandbox = permissions.sandbox;
|
|
1873
|
-
if (userSandbox.network?.allowedDomains)
|
|
1896
|
+
if (userSandbox.network?.allowedDomains) {
|
|
1897
|
+
const domains = userSandbox.network.allowedDomains.filter((d) => d !== void 0);
|
|
1898
|
+
allowedDomains = [...allowedDomains, ...domains];
|
|
1899
|
+
}
|
|
1874
1900
|
if (userSandbox.filesystem) {
|
|
1875
|
-
if (userSandbox.filesystem.allowWrite) allowWrite = userSandbox.filesystem.allowWrite;
|
|
1876
|
-
if (userSandbox.filesystem.denyRead)
|
|
1901
|
+
if (userSandbox.filesystem.allowWrite) allowWrite = userSandbox.filesystem.allowWrite.map(resolveFilesystemPath).filter((p) => p !== void 0);
|
|
1902
|
+
if (userSandbox.filesystem.denyRead) {
|
|
1903
|
+
const deniedPaths = userSandbox.filesystem.denyRead.map(resolveFilesystemPath).filter((p) => p !== void 0);
|
|
1904
|
+
denyRead = [...denyRead, ...deniedPaths];
|
|
1905
|
+
}
|
|
1877
1906
|
}
|
|
1878
1907
|
}
|
|
1879
1908
|
return {
|
|
@@ -1885,7 +1914,8 @@ function buildSandboxConfig(permissions) {
|
|
|
1885
1914
|
denyRead,
|
|
1886
1915
|
allowWrite,
|
|
1887
1916
|
denyWrite: PROTECTED_PATHS.alwaysDenyWrite
|
|
1888
|
-
}
|
|
1917
|
+
},
|
|
1918
|
+
allowPty: true
|
|
1889
1919
|
};
|
|
1890
1920
|
}
|
|
1891
1921
|
/**
|
|
@@ -1904,9 +1934,13 @@ function formatPermissionsSummary(permissions) {
|
|
|
1904
1934
|
summary.push(`• Network: ${domains}${more}`);
|
|
1905
1935
|
}
|
|
1906
1936
|
if (config.filesystem.allowWrite.length > 1 || config.filesystem.allowWrite.length === 1 && config.filesystem.allowWrite[0] !== currentDir) {
|
|
1907
|
-
const
|
|
1908
|
-
|
|
1909
|
-
|
|
1937
|
+
const homeDir = homedir();
|
|
1938
|
+
if (config.filesystem.allowWrite.includes(homeDir)) summary.push("• Filesystem write: All non-sensitive directories");
|
|
1939
|
+
else {
|
|
1940
|
+
const dirs = config.filesystem.allowWrite.map((p) => p === currentDir ? "current directory" : p).slice(0, 2).join(", ");
|
|
1941
|
+
const more = config.filesystem.allowWrite.length > 2 ? ` +${config.filesystem.allowWrite.length - 2} more` : "";
|
|
1942
|
+
summary.push(`• Filesystem write: ${dirs}${more}`);
|
|
1943
|
+
}
|
|
1910
1944
|
}
|
|
1911
1945
|
if (permissions?.sandbox?.filesystem?.denyRead) summary.push(`• Filesystem read denied: ${permissions.sandbox.filesystem.denyRead.length} path(s)`);
|
|
1912
1946
|
return summary;
|
|
@@ -2320,9 +2354,13 @@ const ENTRY_CANDIDATES = [
|
|
|
2320
2354
|
];
|
|
2321
2355
|
/**
|
|
2322
2356
|
* Resolve entry point for a kly app
|
|
2323
|
-
* Priority:
|
|
2357
|
+
* Priority: convention candidates > main field
|
|
2358
|
+
*
|
|
2359
|
+
* We prioritize convention-based source files over package.json main field
|
|
2360
|
+
* because remote apps are run from source, not from built artifacts.
|
|
2324
2361
|
*/
|
|
2325
2362
|
function resolveEntryPoint(repoPath) {
|
|
2363
|
+
for (const candidate of ENTRY_CANDIDATES) if (existsSync(join(repoPath, candidate))) return candidate;
|
|
2326
2364
|
const pkgPath = join(repoPath, "package.json");
|
|
2327
2365
|
if (existsSync(pkgPath)) try {
|
|
2328
2366
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
@@ -2330,7 +2368,6 @@ function resolveEntryPoint(repoPath) {
|
|
|
2330
2368
|
if (existsSync(join(repoPath, pkg.main))) return pkg.main;
|
|
2331
2369
|
}
|
|
2332
2370
|
} catch {}
|
|
2333
|
-
for (const candidate of ENTRY_CANDIDATES) if (existsSync(join(repoPath, candidate))) return candidate;
|
|
2334
2371
|
return null;
|
|
2335
2372
|
}
|
|
2336
2373
|
/**
|
|
@@ -2703,20 +2740,40 @@ async function executeApp(ref, repoPath, args$1, mcp) {
|
|
|
2703
2740
|
const prevRemoteRef = process.env[ENV_VARS.REMOTE_REF];
|
|
2704
2741
|
process.env[ENV_VARS.REMOTE_REF] = remoteRef;
|
|
2705
2742
|
try {
|
|
2706
|
-
const { getAppIdentifier: getAppIdentifier$1, checkApiKeyPermission: checkApiKeyPermission$1, getAppSandboxConfig: getAppSandboxConfig$1 } = await import("./permissions-
|
|
2707
|
-
const { launchSandbox: launchSandbox$1 } = await import("./launcher-
|
|
2743
|
+
const { getAppIdentifier: getAppIdentifier$1, checkApiKeyPermission: checkApiKeyPermission$1, getAppSandboxConfig: getAppSandboxConfig$1 } = await import("./permissions-C_WgoA3t.mjs");
|
|
2744
|
+
const { launchSandbox: launchSandbox$1 } = await import("./launcher-Ex3ynZdE.mjs");
|
|
2745
|
+
const { buildSandboxConfig: buildSandboxConfig$1, formatPermissionsSummary: formatPermissionsSummary$1 } = await import("./config-builder-D5EtwOB3.mjs");
|
|
2746
|
+
const { extractAppPermissions: extractAppPermissions$1 } = await import("./permissions-extractor-BfUPS0Tr.mjs");
|
|
2708
2747
|
const appId = getAppIdentifier$1();
|
|
2748
|
+
console.log("📋 Reading app permissions...");
|
|
2749
|
+
const declaredPermissions = await extractAppPermissions$1(absoluteEntryPath);
|
|
2750
|
+
if (declaredPermissions) {
|
|
2751
|
+
const summary = formatPermissionsSummary$1(declaredPermissions);
|
|
2752
|
+
if (summary.length > 0) {
|
|
2753
|
+
console.log("\nThis app requests the following permissions:");
|
|
2754
|
+
for (const item of summary) console.log(item);
|
|
2755
|
+
console.log("");
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2709
2758
|
console.log("🔐 Checking permissions...");
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2759
|
+
let allowApiKey = false;
|
|
2760
|
+
let sandboxConfig = null;
|
|
2761
|
+
if (declaredPermissions?.apiKeys) {
|
|
2762
|
+
allowApiKey = await checkApiKeyPermission$1(appId);
|
|
2763
|
+
if (!allowApiKey) {
|
|
2764
|
+
console.error("❌ Permission denied: API key access rejected");
|
|
2765
|
+
process.exit(1);
|
|
2766
|
+
}
|
|
2714
2767
|
}
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2768
|
+
if (declaredPermissions) sandboxConfig = buildSandboxConfig$1(declaredPermissions);
|
|
2769
|
+
else {
|
|
2770
|
+
sandboxConfig = await getAppSandboxConfig$1(appId);
|
|
2771
|
+
if (!sandboxConfig) {
|
|
2772
|
+
console.error("❌ Permission denied: Sandbox configuration rejected");
|
|
2773
|
+
process.exit(1);
|
|
2774
|
+
}
|
|
2719
2775
|
}
|
|
2776
|
+
if (!sandboxConfig.filesystem.allowWrite.includes(repoPath)) sandboxConfig.filesystem.allowWrite.push(repoPath);
|
|
2720
2777
|
if (mcp) {
|
|
2721
2778
|
console.warn("⚠️ MCP mode with remote repos not yet fully supported in new architecture");
|
|
2722
2779
|
process.env[ENV_VARS.MCP_MODE] = "true";
|
|
@@ -2728,6 +2785,7 @@ async function executeApp(ref, repoPath, args$1, mcp) {
|
|
|
2728
2785
|
scriptPath: absoluteEntryPath,
|
|
2729
2786
|
args: args$1,
|
|
2730
2787
|
appId,
|
|
2788
|
+
invokeDir: process.cwd(),
|
|
2731
2789
|
sandboxConfig,
|
|
2732
2790
|
allowApiKey
|
|
2733
2791
|
});
|
|
@@ -2799,6 +2857,7 @@ async function main() {
|
|
|
2799
2857
|
}
|
|
2800
2858
|
async function runFile(filePath, appArgs) {
|
|
2801
2859
|
const absolutePath = resolve(process.cwd(), filePath);
|
|
2860
|
+
const invokeDir = process.cwd();
|
|
2802
2861
|
const prevLocalRef = process.env.KLY_LOCAL_REF;
|
|
2803
2862
|
process.env.KLY_LOCAL_REF = `local:${absolutePath}`;
|
|
2804
2863
|
try {
|
|
@@ -2823,6 +2882,7 @@ async function runFile(filePath, appArgs) {
|
|
|
2823
2882
|
scriptPath: absolutePath,
|
|
2824
2883
|
args: appArgs,
|
|
2825
2884
|
appId,
|
|
2885
|
+
invokeDir,
|
|
2826
2886
|
sandboxConfig,
|
|
2827
2887
|
allowApiKey
|
|
2828
2888
|
});
|
|
@@ -2884,5 +2944,5 @@ main().catch((err) => {
|
|
|
2884
2944
|
});
|
|
2885
2945
|
|
|
2886
2946
|
//#endregion
|
|
2887
|
-
export {
|
|
2947
|
+
export { getAppIdentifier as a, listPermissions as c, savePermissions as d, launchSandbox as f, clearAllPermissions as i, loadPermissions as l, formatPermissionsSummary as n, getAppName as o, checkApiKeyPermission as r, getAppSandboxConfig as s, buildSandboxConfig as t, revokePermission as u };
|
|
2888
2948
|
//# sourceMappingURL=kly.mjs.map
|